特定页面请求操作的音频持续时间 NaN
Audio duration NaN on certain page request action
我一直在尝试使用 HTML5 和 Jquery 创建我的自定义媒体播放器。
我采用了不同的方法,并且 运行 根据我刷新页面的方式遇到了一些麻烦。
第一个案例
$(document).ready(function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
在这种情况下,当我通过按地址栏中的 ENTER
键将页面重定向到相同的 URL 时,持续时间 returns 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 浏览器中的错误,但我找不到任何结论性或有用的信息。
这种奇怪行为背后的原因可能是什么?
如果你能把它和这个问题的解决方案一起解释就太好了。
编辑:
我主要是在寻找这种行为差异背后的解释。我想了解在重定向和刷新的情况下渲染页面背后的机制。
听起来问题是事件处理程序设置得太晚了,即音频文件甚至在文档准备好之前就已经加载了它的元数据。
尝试通过删除 $(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();
});
根据 w3 spec,这是持续时间 returns 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(){...});
或
你可以试试:
<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>
请注意,不同浏览器的行为会有所不同。在 Chrome,您有不同类型的加载。当资源不在 cache
中时,它将获取完整文件(例如 js 或 css),或者文件的一部分(例如 mp3)。此部分文件包含 metadata
,允许浏览器确定持续时间和其他数据,例如以该速率下载整个文件所需的时间,例如触发 canplay
或 canplaythrough
事件。如果您查看开发控制台中的网络使用情况,您会看到 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)
}
您会发现,根据刷新方式的不同,这些事件可能会在不同时刻发生,这可能解释了输出中的不一致。
可爱的代码示例和来自人们的东西 - 但解释实际上非常简单。
如果文件已经在缓存中,那么 loadedmetadata
事件将不会触发(许多其他事件也不会触发 - 主要是因为它们在您附加侦听器时已经触发)并且duration
将被设置。如果它不在缓存中,那么 duration
将是 NaN
,事件将触发。
解决方案有点简单。
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]);
}
我在代码注释中包含了 jQuery 个备选方案。
我一直在尝试使用 HTML5 和 Jquery 创建我的自定义媒体播放器。
我采用了不同的方法,并且 运行 根据我刷新页面的方式遇到了一些麻烦。
第一个案例
$(document).ready(function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
在这种情况下,当我通过按地址栏中的 ENTER
键将页面重定向到相同的 URL 时,持续时间 returns 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 浏览器中的错误,但我找不到任何结论性或有用的信息。
这种奇怪行为背后的原因可能是什么? 如果你能把它和这个问题的解决方案一起解释就太好了。
编辑: 我主要是在寻找这种行为差异背后的解释。我想了解在重定向和刷新的情况下渲染页面背后的机制。
听起来问题是事件处理程序设置得太晚了,即音频文件甚至在文档准备好之前就已经加载了它的元数据。
尝试通过删除 $(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();
});
根据 w3 spec,这是持续时间 returns 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(){...});
或
你可以试试:
<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>
请注意,不同浏览器的行为会有所不同。在 Chrome,您有不同类型的加载。当资源不在 cache
中时,它将获取完整文件(例如 js 或 css),或者文件的一部分(例如 mp3)。此部分文件包含 metadata
,允许浏览器确定持续时间和其他数据,例如以该速率下载整个文件所需的时间,例如触发 canplay
或 canplaythrough
事件。如果您查看开发控制台中的网络使用情况,您会看到 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)
}
您会发现,根据刷新方式的不同,这些事件可能会在不同时刻发生,这可能解释了输出中的不一致。
可爱的代码示例和来自人们的东西 - 但解释实际上非常简单。
如果文件已经在缓存中,那么 loadedmetadata
事件将不会触发(许多其他事件也不会触发 - 主要是因为它们在您附加侦听器时已经触发)并且duration
将被设置。如果它不在缓存中,那么 duration
将是 NaN
,事件将触发。
解决方案有点简单。
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]);
}
我在代码注释中包含了 jQuery 个备选方案。