setTimeout 函数是否足够准确以与音频时序同步?

Is setTimeout function accurate enough to sync with audio timing?

我想播放音乐(使用 HTML5 音频)并在特定时间显示一些图形元素(应与音频时间同步)。

用JavaScript的window.setTimeout函数可以吗?

setTimeout(function() {
    requestAnimationFrame(function() {
        // display something
    });
}, 1400);

setTimeout(function() {
    requestAnimationFrame(function() {
        // display something else
    });
}, 2300);

或者,有没有更好的方法来做到这一点?

如果您能够在音频开始的同时开始超时,那么它就足够准确了。例如,对于 60 Hz 的屏幕频率,您有 16 毫秒到下一帧,因此实际上不必那么准确。

根据您所显示的内容,即使有几帧偏移也是可以接受的。例如,动画电影以 12 Hz 的频率更新(电影电影以 24 Hz 运行,动画每隔一帧更新一次)。

但是请注意,超时回调与其他所有内容都在同一线程上运行,因此只有在您没有任何其他 运行 占用主线程太长时间的情况下,它才会准确。例如,如果您有一些其他的事件处理程序执行一些繁重的工作,则可能会将超时延迟到足以可见的程度。

"Accurate enough"是主观的,但总的来说,没有。您不知道音频何时会完成下载并开始播放,或者它是否会在没有缓冲或被用户暂停的情况下播放。

相反,您可以使用 timeupdate 事件和 currentTime 属性,将事件正确同步到时间线。

var exampleElement = document.getElementById('example');
var lastTime = 0;
exampleElement.addEventListener('timeupdate', function(e) {
  var nowTime = this.currentTime;
  //Check if just passed the 1.4 second time mark.
  if (nowTime > 1.4 && lastTime < 1.4) {
    //Add a message to the debug element.
    var logElement = document.getElementById('log');
    logElement.textContent += 'Do something at 1.4 seconds\n';
  }
  lastTime = nowTime;
});
<audio id="example" controls="controls" autoplay="autoplay">
  <source src="http://media.w3.org/2010/07/bunny/04-Death_Becomes_Fur.mp4" type='audio/mp4'>
  <source src="http://media.w3.org/2010/07/bunny/04-Death_Becomes_Fur.oga" type='audio/ogg; codecs=vorbis'>
</audio>
<pre id="log"></pre><!--debug element-->

setTimeout 通常只在 给定的延迟后,并且当浏览器的线程清空时才执行

所以不,它并不完全准确,但我认为就您的目的而言,它已经足够接近了,通常延迟不到 0.2%,

图片来自this question

然而,在较慢的用户机器上,效果可能更明显,使用 setTimeout isn't recommended.

相反,您可以使用 timeupdate 事件和 currentTime 属性 来更准确地匹配音频,

var audio = document.querySelector('audio#my-audio');

audio.addEventListener('timeupdate', function(){
  switch (this.currentTime){
    case 1:
      //stuff
      break;
    /* etc. */
  }
}

currentTime 虽然使用秒来计数,因此您将不得不使用不太精确的节拍器,但准确度就在那里。