2015-06-11 11 views
7

Ho cercato di creare il mio lettore multimediale personalizzato utilizzando HTML5 e Jquery.Durata audio NaN su determinate azioni di richiesta di pagina

Ho seguito approcci diversi e ho incontrato alcuni problemi in base al mio modo di aggiornare la pagina.

primo caso

$(document).ready(function(){ 
    duration = Math.ceil($('audio')[0].duration); 
    $('#duration').html(duration); 
}); 

In questo caso, la durata restituisce NaN quando ho reindirizzare la pagina allo stesso URL premendo il tasto ENTER nella barra degli indirizzi. Tuttavia, funziona perfettamente quando si aggiorna utilizzando lo reload button o premendo il pulsante F5.

Secondo caso

Ho letto in alcune risposte che la durata di carico dopo l'evento loadedmetadata potrebbe aiutare. Così ho provato la seguente:

$(document).ready(function(){ 
    $('audio').on('loadedmetadata', function(){ 
     duration = Math.ceil($('audio')[0].duration); 
     $('#duration').html(duration); 
    }); 
}); 

Sorprendentemente, in questo caso, l'inverso del primo caso è accaduto. La durata viene visualizzata completamente bene nel caso di un reindirizzamento, ovvero premendo ENTER nella barra degli indirizzi. Tuttavia, nel caso di aggiornamento utilizzando il pulsante F5 o reload button, la durata non viene visualizzata affatto, nemmeno NaN che mi ha portato a credere che il codice non venga eseguito affatto.


Ulteriore lettura suggerito che questo potrebbe essere un bug nei browser WebKit, ma non ho trovato nulla di conclusivo o utile.

Quale potrebbe essere la causa di questo comportamento particolare? Sarebbe bello se potessi spiegarlo insieme alla soluzione a questo problema.

Modifica: Sono principalmente alla ricerca di una spiegazione dietro questa differenza di comportamento. Mi piacerebbe capire il meccanismo alla base del rendering di una pagina nel caso di reindirizzamento e aggiornamento.

risposta

3

Sembra che il problema è che il gestore eventi è impostato troppo tardi, vale a dire che il file audio ha caricato i suoi metadati prima che il documento sia pronto.

provare a impostare il gestore di eventi nel più breve tempo possibile rimuovendo la chiamata $(document).ready:

$('audio').on('loadedmetadata', function(){ 
    duration = Math.ceil($('audio')[0].duration); 
    $('#duration').html(duration); 
}); 

Si noti che questo richiede che il tag <script> sia dopo il tag <audio> nel documento.

In alternativa, è possibile modificare la logica un po ', in modo che il codice che aggiorna la durata corre sempre (ma non riesce con grazia se si ottiene un NaN): comportamento standard

function updateDuration() { 
    var duration = Math.ceil($('audio')[0].duration); 
    if (duration) 
     $('#duration').html(duration); 
} 

$(document).ready(function(){ 
    $('audio').on('loadedmetadata', updateDuration); 
    updateDuration(); 
}); 
+0

Farò un tentativo e tornerò da te. –

+0

No. Ancora non funziona. La cosa più particolare è il modo in cui si comporta diversamente nel caso di reindirizzamento rispetto all'aggiornamento della pagina. Qual è la differenza tra l'uno in termini di sequenza di caricamento della pagina? –

+0

Sì, ho provato tre diversi casi ora. Il caricamento e il ricaricamento di entrambi restituiscono lo stesso comportamento. –

0

Secondo w3 spec questo è quando la durata restituisce NaN. Quindi suggerisco usare durationchange evento:

$('audio').on('durationchange', function(){ 
    var duration = $('audio')[0].duration; 
    if(!isNaN(duration)) { 
     $('#duration').html(Math.ceil(duration)); 
    } 
}); 

NOTA: Questo codice (e la vostra troppo) non funzionerà correttamente nel caso in cui se si dispone di più di un audio elemento sulla pagina. Il motivo è che si ascolta gli eventi da tutte le audio elementi di pagina e ogni elemento si attiverà proprio evento:

$('audio').on('durationchange', function(){...}); 

O

si può provare:

<script> 
     function durationchange() { 
      var duration = $('audio')[0].duration; 
      if(!isNaN(duration)) { 
       $('#duration').html(Math.ceil(duration)); 
      } 
     } 
    </script> 

    <audio ondurationchange="durationchange()"> 
     <source src="test.mp3" type="audio/mpeg"> 
    </audio> 
+0

Ho un solo file audio e l'evento di modifica della durata restituisce la stessa risposta. –

0

Nota che i comportamenti saranno diversi da un browser ad un altro. Su Chrome, hai diversi tipi di caricamento. Quando le risorse non sono in cache, recupererà il file completo (per esempio js o css), o una parte del file (per esempio mp3). Questo file parziale contiene metadata che consente al browser di determinare la durata e altri dati, ad esempio il tempo necessario per scaricare l'intero file a questa velocità, attivando ad esempio gli eventi canplay o canplaythrough. Se guardi l'utilizzo della rete nella tua console di sviluppo, vedrai che lo HTTP status code sarà 200 (carico di successo) o 206 (carico parziale, per esempio per mp3).

Quando si colpisce refresh, gli elementi vengono controllati per vedere se sono cambiati. Lo stato HTTP sarà quindi 304, il che significa che il file non è stato modificato. Se non è cambiato ed è ancora nella cache del browser, non verrà scaricato. La chiamata per determinare se è stata modificata o meno viene dal server che fornisce il file.

Quando fai semplicemente clic su inserisci nella barra degli indirizzi, viene automaticamente prelevato dalla cache, non convalidando online. Quindi è molto più veloce.

Quindi, a seconda di come chiami o aggiorni la tua pagina (sia che entri, aggiorni o completi l'aggiornamento senza cache), avrai grandi differenze nel momento in cui prendi il metadata dal tuo mp3. Tra il prelievo diretto dei metadati dalla cache e l'inoltro di una richiesta a un server, la differenza può essere di alcune centinaia di millisecondi, il che è sufficiente per modificare i dati disponibili in momenti diversi.

Detto questo, l'ascolto di loadedmetada dovrebbe dare risultati coerenti. Questo evento viene attivato quando vengono caricati i dati con informazioni sulla durata, quindi indipendentemente dal modo in cui la pagina viene caricata, non dovrebbe importare se quella chiamata è stata eseguita correttamente. A questo punto devi considerare forse qualche interferenza da altri elementi. Quello che dovresti fare è seguire l'audio attraverso vari eventi per ottenere esattamente dove è in momenti diversi. Quindi nel tuo documento pronto puoi aggiungere ascoltatori per diversi eventi e vedere dove si verifica il problema. Come questo:

$('audio')[0].addEventListener('loadstart', check_event) 
$('audio')[0].addEventListener('loadeddata', check_event) 
$('audio')[0].addEventListener('loadedmetadata', check_event)//at this point you should be able to call duration 
$('audio')[0].addEventListener('canplay', check_event) //and so on 

function check_event(e) { 
    console.log(e.target, e.type) 
} 

Vedrai che a seconda del modo in cui si aggiorna, questi eventi possono venire in diversi momenti, forse spiegando incongruenze nelle vostre uscite.

+0

Anche nel caso dell'evento 'loadedmetadata', non c'è differenza nell'output, ho provato per tutti i 7 possibili eventi. –

+0

Forse un problema con il file allora? È possibile aggiungere console.log (e.target, e.type, e.target.duration) per ottenere esattamente quando è possibile ottenere la durata. –

+0

Voglio capire perché c'è una differenza tra reindirizzamento e aggiornamento, è perché uno recupera i metadati dalla cache mentre l'altro no? Questo è quello che sto assumendo. A partire da ora, sono riuscito a farlo funzionare mettendo un ritardo di 1 secondo tra i diversi callback dell'evento, ma non è il modo ideale di andare. –

1

Esempi di codice belli e cose da persone - ma la spiegazione è in realtà molto semplice.

Se il file è già nella cache allora l'evento loadedmetadata non viene emesso (né una serie di altri eventi - fondamentalmente perché hanno già sparato nel momento in cui collegare i vostri ascoltatori) e sarà impostato il duration. Se non è nella cache, lo duration sarà NaN e l'evento verrà attivato.

La soluzione è una specie di semplice.

function runWhenLoaded() { /* read duration etc, this = audio element */ } 

if (!audio.readyState) { // or $audio[0].readyState 
    audio.addEventListener("loadedmetadata", runWhenLoaded); 
    // or $audio.on("loadedmetadata", runWhenLoaded); 
} else { 
    runWhenLoaded.call(audio); 
    // or runWhenLoaded.call($audio[0]); 
} 

Ho incluso le alternative jQuery nei commenti del codice.

+0

Cosa succede nella parte opposta del codice? –

+1

Fondamentalmente hai un bel po 'di codice che vuoi chiamare quando puoi ascoltare l'audio, controlliamo se il readyState è qualsiasi 0 (cioè non ha nemmeno i metadati) - in tal caso aggiungiamo l'evento, se no (c'è metadata, o anche l'intero file) quindi chiamiamo direttamente la funzione - usando '' '.call (this)' '' ci permette di impostare il valore '' this''' su esattamente come se fosse un evento - quindi non è necessario modificare il codice – Rycochet

+0

Non sapevo del metodo .call(). +1 per questa tecnica. –

Problemi correlati