setTimeout在MIDI.js中触发太晚



我正在使用MIDI.js与几种乐器一起播放MIDI文件。

以下内容执行太晚我怎样才能解决这个问题呢?

  • 歌曲的第一个音符。像所有的笔记一样,它们是通过AudioBufferSourceNodestart()来安排的。
  • MIDI程序变更事件。他们是通过这里的setTimeout安排的。他们的"lateness">

当我停止歌曲并重新开始时,不再有问题,但delay值非常相似。因此,delay值可能不是问题的原因。

(我使用最新的官方分支(命名为" abcj"),因为"大师"分支较旧,并且在此类MIDI文件中存在更多问题。)

JavaScript事件循环就是这样工作的。

呼叫setTimeout…在给定的时间间隔后不执行回调函数。

执行取决于队列中等待任务的数量。

…延迟是运行时处理请求所需的最小时间(不是保证时间)。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop zero_delays

您可以使用window.requestAnimationFrame()来代替setTimeout(),并自行计算延迟的经过时间。

windows . requestanimationframe () - Web api | MDN

window.requestAnimationFrame()方法告诉浏览器您希望执行动画,并请求浏览器在下次重绘之前调用指定的函数来更新动画。该方法接受一个回调函数作为参数,在重新绘制之前调用。

…将请求在浏览器执行下一次重绘之前调用动画函数。回调的次数通常为每秒60次,但通常会匹配大多数web浏览器中的显示刷新率

https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

performance.now() - Web api | MDNhttps://developer.mozilla.org/en-US/docs/Web/API/Performance/now

在我们的情况下,我们不想做任何动画,而只想使用它来获得更高精度的超时。

const delayMs = 1000;
const startTime = performance.now();
function delay(func) {
const delayStartTime = performance.now();
function delayStep() {
// Run again if still elapsed time is less than a delay
if (performance.now() - delayStartTime <= delayMs) {
window.requestAnimationFrame(delayStep);
}
else
{
// Run the delayed function
func();
}
}

// Run first time
window.requestAnimationFrame(delayStep);
}
// Trying `setTimeout()`
setTimeout(() => doSomeJob('setTimeout()'), delayMs);
// Trying `delay()`
delay(() => doSomeJob('delay()'));
// Function that we'd like to run with a delay
function doSomeJob(marker)
{
const elapsedTime = performance.now() - startTime;
console.log(`${marker}: Ran after ${elapsedTime / 1000} seconds`);
}

如果你多次运行它,你会发现delay()几乎总是比setTimeout()好。差异非常小,因为页面上没有发生任何其他事情。如果有一些密集的运行,setTimeout()应该表现出更差的"精度"。

最新更新