应优先监听 loadedmetadata 事件获取首次时长,再用 durationchange 动态更新;每次读取 duration 都需 isfinite() 校验,避免 nan 或 infinity 导致错误。

不能单靠 durationchange 获取准确时长,它只是“通知变化”的信号,不是“保证就绪”的时机。真正可靠的方式是:用 loadedmetadata 事件作为主入口,再配合 durationchange 做动态更新兜底。
为什么 durationchange 本身不足够
durationchange 在视频时长从 NaN 变为具体数值、或从一个值变为另一个值(如 MSE 动态拼接、直播流切换)时触发。但它有三个关键限制:
- 可能触发多次(比如元数据加载中反复修正时长)
- 可能在
loadedmetadata之前就触发一次(此时duration仍为NaN) - 对直播流或损坏资源,它也可能触发,但
duration是Infinity或仍为NaN
正确组合使用 loadedmetadata + durationchange
最稳妥的写法是双监听,分工明确:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
首次获取:绑定
loadedmetadata,这是元数据解析完成的标志性事件,此时duration第一次可用(除非是直播) -
后续更新:同时监听
durationchange,用于响应动态场景(如分片视频加载新段、MSE appendBuffer 后时长重算)
示例代码:
const video = document.getElementById('myVideo');
const handleDurationReady = () => {
if (isFinite(video.duration)) {
console.log('总时长:', Math.round(video.duration), '秒');
} else if (video.duration === Infinity) {
console.log('直播流,无固定时长');
} else {
console.warn('时长不可用,请检查资源');
}
};
video.addEventListener('loadedmetadata', handleDurationReady);
video.addEventListener('durationchange', handleDurationReady);
必须做的安全判断
无论在哪次事件里读 duration,都需校验有效性,不能直接计算或显示:
- 用
isFinite(video.duration)判断是否为有效数字(排除NaN和Infinity) - 避免用
typeof video.duration === 'number',因为NaN也是 number 类型 - 对
Infinity,UI 上应显示“直播中”或隐藏进度条,而不是尝试除法计算百分比
常见误操作及规避方式
以下做法容易导致拿不到时长或报错:
- 在设置
src后立刻读video.duration→ 改为监听事件后再读 - 只监听
durationchange并假设它一定给出有效值 → 必须加isFinite判断 - 用
loadstart或canplay替代loadedmetadata→ 这两个事件发生时duration可能仍未就绪 - 动态插入
<video></video>元素后没调用load()→ 需手动触发预加载










