Javascript `结束了Firefox 87、88和89中无休止地触发的事件

Javascript `结束了Firefox 87、88和89中无休止地触发的事件,javascript,firefox,audio,Javascript,Firefox,Audio,我创建了一个小脚本来重现这个问题 const audio = document.createElement( 'audio' ) let i = 0 audio.onended = (e) => { i++ requestAnimationFrame( () => console.log( `ended ${i} time${i>1?'s':''}, audio is ${audio.paused?'':'not '}paused`) ) } audio.onc

我创建了一个小脚本来重现这个问题

const audio = document.createElement( 'audio' )
let i = 0
audio.onended = (e) => {
    i++
    requestAnimationFrame( () => console.log( `ended ${i} time${i>1?'s':''}, audio is ${audio.paused?'':'not '}paused`) )
}
audio.oncanplaythrough = (e) => {
    audio.pause()
    audio.currentTime = audio.duration
}
audio.src = 'https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3'
该脚本创建一个
audio
元素、一个
oneded
回调函数,该函数在控制台中打印事件被触发的次数,以及一个
oncanplaythrough
回调函数,该函数通过编程将
currentTime
设置为音频文件的
duration
。在
oneded
回调函数中,我引入了
requestAnimationFrame
调用,其唯一目的是防止浏览器因Firefox中触发大量
end
事件而失去响应

脚本一运行,就可以验证Firefox是否无休止地触发
结束
事件,尽管音频元素已暂停。这种行为发生在Firefox 87以及Firefox Beta 88.0b9Firefox每晚89.0a1

ChromeEdge中,只要触发
canplaythrough
,就会触发一次
end
事件,从而将
currenTime
设置为文件的结尾

Safari中,从不触发
end
事件,考虑到音频元素已
暂停
,并且
currentTime
以编程方式设置为文件结尾,我认为这应该是预期的行为

Chrome/Edge和Safari中行为的区别在于解释

播放流媒体已停止时,将触发结束事件,原因是已到达媒体的结尾或没有其他可用数据

根据该定义,Safari似乎是实现正确行为的唯一浏览器:如果音频元素被暂停,只需在文件末尾设置
currentTime
,就不会触发任何
ended
事件,因为音频元素:

  • 没有回击
  • 尚未停止,因为它已暂停
  • 由于
    currentTime
    是以编程方式设置的,因此未到达文件末尾
  • 无论上述定义的正确解释是什么,持续触发的
    事件
    ——就像Firefox中发生的那样——都不是预期的行为,尤其是当音频元素暂停时

    我是否遗漏了什么,或者这是Firefox中的一个bug

    更新

    我最初发布的脚本有点误导,因为设置
    currentTime
    总是触发
    canplaythrough
    事件。因此,
    oncanplaythrough
    回调递归地触发自身。但是不同浏览器之间的不同行为是因为Firefox是唯一一个
    audio.currentTime=audio.duration
    会触发
    end
    事件的浏览器,即使
    audio.currentTime
    已经等于
    audio.duration

    我创建了一个片段来测试不同浏览器之间的差异

    const audio=document.querySelector(“#demo”)
    const button=document.querySelector(“#jump”)
    const output=document.querySelector(“#output”)
    设i=0
    button.onclick=(e)=>{
    audio.currentTime=audio.duration
    }
    audio.onended=(e)=>{
    我++
    常量p=document.createElement('p')
    p、 innerHTML=`曲目结束${i}时间${i>1?'s':'}`
    output.innerHTML=p.outerHTML
    }
    body{font-family:sans-serif;}
    
    反复单击“跳到终点”按钮

    在Safari中,除非玩家当前正在玩,否则不会触发任何
    end
    事件。一旦播放机到达音频文件的末尾,将不再生成
    end
    事件

    在Chrome/Edge中,
    结束
    事件只触发一次,无论玩家正在玩或暂停

    在Firefox中,
    end
    事件会在每次单击按钮时触发,而不管播放器正在播放或暂停

    跳到底