某些页面请求操作的音频持续时间NaN

时间:2015-06-11 00:08:07

标签: javascript jquery html5 html5-audio

我一直在尝试使用HTML5和Jquery创建自定义媒体播放器。

我遵循不同的方法,并根据我刷新页面的方式遇到了一些麻烦。

第一个案例

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

在这种情况下,当我通过按地址栏中的ENTER键将页面重定向到同一URL时,持续时间返回NaN。但是,当我使用reload button或按F5按钮进行刷新时,它完全正常。

第二种情况

我在一些答案中读到loadedmetadata事件后的加载持续时间可能会有所帮助。所以我尝试了以下内容:

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

令人惊讶的是,在这种情况下,发生了第一种情况的反转。在重定向的情况下,持续时间显示完全正常,即在地址栏中按ENTER。但是,在使用F5按钮或reload button进行刷新的情况下,持续时间根本不会显示,甚至NaN也不会导致我认为代码没有被执行所有

进一步阅读建议这可能是webkit浏览器中的一个错误,但我找不到任何结论性或有帮助的。

这种奇特行为背后的原因是什么? 如果你能解释它并解决这个问题,那就太棒了。

编辑: 我主要是在寻找这种行为差异背后的解释。我想了解在重定向和刷新的情况下渲染页面背后的机制。

4 个答案:

答案 0 :(得分:3)

听起来问题是事件处理程序设置得太晚,即音频文件在文档准备好之前加载了元数据。

尝试删除$(document).ready调用

,尽快设置事件处理程序
$('audio').on('loadedmetadata', function(){
    duration = Math.ceil($('audio')[0].duration);
    $('#duration').html(duration);
});

请注意,这需要<script>标记位于文档中的<audio>标记之后。

或者,您可以略微调整逻辑,以便更新持续时间的代码始终运行(但如果获得NaN则优雅地失败):

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

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

答案 1 :(得分:1)

可爱的代码示例和来自人们的东西 - 但解释实际上非常简单。

如果文件已经在缓存中,那么loadedmetadata事件将不会触发(也不会触发许多其他事件 - 主要是因为它们在您附加侦听器时已经触发)和{{ 1}}将被设置。如果它不在缓存中,则duration将为duration,并且该事件将会触发。

解决方案很简单。

NaN

我在代码注释中包含了jQuery备选方案。

答案 2 :(得分:0)

根据w3 spec,当持续时间返回NaN时,这是标准行为。 所以我建议使用durationchange事件:

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

注意:如果您在页面上有多个audio元素,则此代码(以及您的代码)将无法正常工作。原因是您从页面上的所有audio元素中侦听事件,并且每个元素将触发自己的事件:

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

OR

您可以尝试:

    <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>

答案 3 :(得分:0)

请注意,不同浏览器的行为会有所不同。在Chrome上,您有不同类型的加载。当资源不在cache时,它将获取完整文件(例如js或css),或者是文件的一部分(例如mp3)。此部分文件包含metadata,允许浏览器确定持续时间和其他数据,例如以此速率下载整个文件所需的时间,例如canplaycanplaythrough事件。如果您查看开发控制台中的网络使用情况,您会看到HTTP status code将是200(成功加载)或206(部分加载 - 例如mp3)。

点击refresh时,会检查元素是否已更改。 HTTP状态将为304,表示文件尚未修改。如果它没有更改并且仍在浏览器缓存中,则不会下载它。确定是否已更改的调用来自提供文件的服务器。

当您只需点击地址栏中的输入时,它就会自动从缓存中获取,而不是在线验证。所以它要快得多。

因此,根据您调用或刷新页面的方式(无论是简单输入,刷新还是完全刷新而不使用缓存),您从mp3获得metadata的那一刻就会有很大差异。在从缓存直接获取元数据与向服务器发出请求之间,差异可能是几百毫秒,这足以改变不同时刻可用的数据。

话虽如此,听loadedmetada应该给出一致的结果。加载具有持续时间信息的数据时会触发此事件,因此无论页面加载的方式如何,都应该正确地进行调用。此时,您必须考虑其他元素的干扰。你应该做的是通过各种事件跟踪你的音频,以获得它在不同时刻的确切位置。因此,在准备好文档时,您可以为不同的事件添加侦听器,并查看问题发生的位置。像这样:

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

您会看到,根据您刷新的方式,这些事件可能会在不同的时刻出现,也许会解释您输出中的不一致。