2015-06-11 5 views
7

Ich habe versucht, meine benutzerdefinierte Media Player mit HTML5 und Jquery zu erstellen.Audiodauer NaN auf bestimmter Seite Anfrage Aktion

Ich habe verschiedene Ansätze verfolgt und in einigen Schwierigkeiten auf der Grundlage meiner Art der Aktualisierung der Seite geriet.

Erster Fall

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

In diesem Fall wird die Dauer Wert NaN zurück, wenn ich die Seite auf die gleiche URL umleiten, indem die ENTER Schlüssel in der Adressleiste drücken. Es funktioniert jedoch völlig in Ordnung, wenn ich unter Verwendung der reload button oder durch Drücken der Taste F5 aktualisieren.

Zweiter Fall

las ich in einigen Antworten, die Ladedauer nach dem loadedmetadata Ereignisse helfen könnte. Also habe ich versucht, die folgenden:

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

überraschenderweise in diesem Fall ist die Umkehrung des ersten Fall geschehen ist. Die Dauer wird im Fall einer Umleitung vollständig angezeigt, d. H. Drücken von ENTER in der Adressleiste. Im Falle der Aktualisierung mit dem F5 Knopf oder dem reload button wird die Dauer überhaupt nicht angezeigt, nicht einmal NaN, was mich zu der Annahme verleitet hat, dass der Code überhaupt nicht ausgeführt wird.

Weiterführende Literatur vorgeschlagen, dies könnte ein Bug innerhalb der Webkit-Browser sein, aber ich konnte nichts schlüssiges oder hilfreich finden.

Was könnte die Ursache für dieses eigenartige Verhalten sein? Es wäre großartig, wenn Sie es zusammen mit der Lösung für dieses Problem erklären könnten.

Edit: Ich suche hauptsächlich nach einer Erklärung hinter diesem Unterschied im Verhalten. Ich möchte den Mechanismus hinter dem Rendern einer Seite im Falle von Redirect und Refresh verstehen.

Antwort

3

Es klingt wie das Problem ist, dass der Event-Handler zu spät eingestellt ist, d. H. Die Audiodatei hat ihre Metadaten geladen, bevor das Dokument überhaupt bereit ist.

Versuchen Sie, die Event-Handler so schnell wie möglich einstellen, indem Sie den $(document).ready Anruf entfernt: im Dokument

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

Beachten Sie, dass dies erfordert, dass der <script> Tag seine nach dem <audio>-Tag.

Alternativ können Sie Ihre Logik leicht optimieren, so dass der Code, der die Dauer immer aktualisiert läuft (aber nicht ordnungsgemäß, wenn es eine NaN bekommt):

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

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

Ich werde es versuchen und auf Sie zurückkommen. –

+0

Nein. Es funktioniert immer noch nicht. Das Seltsamste ist, wie es sich im Falle einer Weiterleitung anders verhält als beim Aktualisieren der Seite. Was ist der Unterschied zwischen den beiden in Bezug auf die Seitenladefolge? –

+0

Ja, ich habe es jetzt in drei verschiedenen Fällen versucht. Hard neu laden und neu laden beide das gleiche Verhalten zurück. –

0

Nach w3 spec dieses Standardverhalten ist, wenn Dauer gibt NaN zurück. Deshalb schlage ich vor durationchange Ereignis verwenden:

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

HINWEIS: Dieser Code (und Ihr auch) wird, falls nicht richtig funktionieren, wenn Sie mehr als ein audio Element auf Seite haben. Der Grund hierfür ist, dass Sie Ereignisse aus allen audio Elementen auf Seite hören und jedes Element wird eigenes Ereignis ausgelöst:

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

ODER

Sie können versuchen:

<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

Ich habe nur eine Audio-Datei und Dauer Änderung Ereignis gibt die gleiche Antwort zurück. –

0

anzumerken, dass Verhaltensweisen von einem unterscheiden Browser zu einem anderen. In Chrome haben Sie unterschiedliche Arten des Ladens. Wenn Ressourcen nicht in cache sind, wird entweder die komplette Datei (für js oder css zum Beispiel), entweder ein Teil der Datei (zum Beispiel mp3), abgerufen. Diese Teildatei enthält metadata, die es dem Browser ermöglicht, die Dauer und andere Daten zu bestimmen, wie beispielsweise die Zeit, die für das Herunterladen der ganzen Datei bei dieser Rate benötigt wird, zum Beispiel canplay oder canplaythrough Ereignisse. Wenn Sie die Netzwerknutzung in Ihrer Entwicklerkonsole betrachten, werden Sie sehen, dass HTTP status code entweder 200 (erfolgreich geladen) oder 206 (teilweise geladen - zum Beispiel für mp3) ist.

Wenn Sie refresh drücken, werden die Elemente überprüft, um festzustellen, ob sie sich geändert haben. Der HTTP-Status lautet dann 304, was bedeutet, dass die Datei nicht geändert wurde. Wenn es sich nicht geändert hat und sich noch im Browser-Cache befindet, wird es nicht heruntergeladen. Der Aufruf, um festzustellen, ob er geändert wurde oder nicht, kommt vom Server, der die Datei bereitstellt.

Wenn Sie einfach in die Adressleiste klicken, wird es automatisch aus dem Cache genommen, nicht online validiert. Es ist also viel schneller.

Je nachdem, wie Sie Ihre Seite aufrufen oder aktualisieren (entweder einfach eingeben, aktualisieren oder komplett ohne Cache aktualisieren), haben Sie große Unterschiede in dem Moment, in dem Sie die von Ihrem MP3-Player erhalten. Zwischen der direkten Übernahme der Metadaten aus dem Cache und der Anforderung an einen Server kann der Unterschied einige hundert Millisekunden betragen, was ausreicht, um zu ändern, welche Daten zu unterschiedlichen Zeitpunkten verfügbar sind.

Das gesagt, hören loadedmetada sollte konsistentes Ergebnis geben. Dieses Ereignis wird ausgelöst, wenn die Daten mit Informationen zur Dauer geladen werden. Es spielt also keine Rolle, ob die aufgerufene Seite ordnungsgemäß geladen wird. An diesem Punkt müssen Sie vielleicht einige Interferenzen von anderen Elementen berücksichtigen. Was Sie tun sollten, ist Ihrem Audio durch verschiedene Ereignisse zu folgen, um genau zu bekommen, wo es in verschiedenen Momenten ist. In Ihrem Dokument können Sie also Listener für verschiedene Ereignisse hinzufügen und sehen, wo das Problem auftritt. Wie folgt aus:

$('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) 
} 

Sie werden sehen, dass auf dem Weg ab, die Sie aktualisieren, diese Ereignisse zu verschiedenen Zeitpunkten kommen können, vielleicht Inkonsistenzen in Ihren Ausgaben zu erklären.

+0

Selbst im Falle eines 'loadedmetadata'-Ereignisses gibt es keinen Unterschied in der Ausgabe, ich habe für alle 7 möglichen Ereignisse getestet. –

+0

Vielleicht ein Problem mit der Datei dann? Sie können console.log (e.target, e.type, e.target.duration) hinzufügen, um genau zu erhalten, wann Sie die Dauer erhalten können. –

+0

Ich möchte verstehen, warum es einen Unterschied zwischen Redirect und Refresh gibt, ist es, weil man die Metadaten aus dem Cache holt, während der andere nicht? Das nehme ich an. Ab sofort konnte ich es mit einer Verzögerung von 1 Sekunde zwischen den verschiedenen Event-Callbacks arbeiten, aber das ist nicht der ideale Weg. –

1

Schöne Codebeispiele und Zeug von Menschen - aber die Erklärung ist eigentlich sehr einfach.

Wenn sich die Datei bereits im Cache befindet, wird das Ereignis loadedmetadata nicht ausgelöst (noch werden eine Reihe anderer Ereignisse ausgelöst, weil sie bereits ausgelöst haben, wenn Sie Ihre Listener anhängen) und die duration wird festgelegt. Wenn es nicht im Cache ist, wird durationNaN sein, und das Ereignis wird ausgelöst.

Die Lösung ist so einfach.

Ich habe die jQuery-Alternativen in den Code-Kommentaren enthalten.

+0

Was passiert im sonst Teil des Codes? –

+1

Im Grunde haben Sie eine Menge Code, den Sie aufrufen möchten, wenn Sie Audio abspielen können, wir prüfen, ob der readyState 0 ist (dh, nicht einmal Metadaten) - wenn ja, dann fügen wir das Ereignis hinzu, wenn nicht (There's Metadaten, oder sogar die ganze Datei), dann rufen wir die Funktion direkt auf - mit '' '.call (this)' '' können wir den '' 'this'''-Wert auf genau den gleichen Wert setzen, als wäre es ein Event - Der Code muss also nicht geändert werden. – Rycochet

+0

Ich wusste nichts über die Methode .call(). +1 für diese Technik. –