对于不阻止I / O的无限循环,是否有更快的替代window.requestAnimationFrame()
?
我在循环中所做的与动画无关,所以我不在乎下一帧何时准备就绪,并且我已经读过window.requestAnimationFrame()
受到显示器刷新率的限制或至少等待直到画出一帧。
我也尝试了以下内容:
function myLoop() {
// stuff in loop
setTimeout(myLoop, 4);
}
(4是因为这是setTimeout
中的最小间隔,较小的值仍然默认为4.)但是,我需要更好的分辨率。
那里有更好的表现吗?
我基本上需要while(true)
的非阻止版本。
答案 0 :(得分:5)
比setTimeout
更早出现的两件事:
process.nextTick
回调(NodeJS特定):
process.nextTick()
方法将回调添加到“下一个滴答队列”。一旦事件循环的当前转弯转到完成,将调用当前在下一个滴答队列中的所有回调。这不是
setTimeout(fn, 0)
的简单别名。效率更高。它在事件循环的后续滴答中触发任何其他I / O事件(包括定时器)之前运行。
承诺结算通知
因此,这些可能是您工具带的工具,将setTimeout
中的一个或两个混合使用,以达到您想要的平衡。
详细说明:
您可能知道,给定的JavaScript线程基于任务队列运行(规范将其称为作业队列);你可能知道,浏览器中有一个主要的默认UI线程,NodeJS运行一个线程。
但事实上,在现代实现中至少有两个任务队列:我们都想到的主要任务队列(其中setTimeout
和事件处理程序放置他们的任务),以及“微任务”队列,其中某些异步操作在处理主任务(或“macrotask”)期间放置。一旦macrotask完成,就会处理这些微任务,在主队列中的下一个macrotask之前 - 即使下一个macrotask在微任务之前排队。
nextTick
回调和承诺结算通知都是微任务。因此,调度要么调度异步回调,要么在下一个主要任务之前进行调度。
我们可以在浏览器中看到setInterval
和承诺解析链:
let counter = 0;
// setInterval schedules macrotasks
let timer = setInterval(() => {
$("#ticker").text(++counter);
}, 100);
// Interrupt it
$("#hog").on("click", function() {
let x = 300000;
// Queue a single microtask at the start
Promise.resolve().then(() => console.log(Date.now(), "Begin"));
// `next` schedules a 300k microtasks (promise settlement
// notifications), which jump ahead of the next task in the main
// task queue; then we add one at the end to say we're done
next().then(() => console.log(Date.now(), "End"));
function next() {
if (--x > 0) {
if (x === 150000) {
// In the middle; queue one in the middle
Promise.resolve().then(function() {
console.log(Date.now(), "Middle");
});
}
return Promise.resolve().then(next);
} else {
return 0;
}
}
});
$("#stop").on("click", function() {
clearInterval(timer);
});
<div id="ticker"> </div>
<div><input id="stop" type="button" value="Stop"></div>
<div><input id="hog" type="button" value="Hog"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
当你运行它并点击 Hog 按钮时,请注意计数器显示如何冻结,然后再继续。这是因为在它之前安排了300,000个微型计划。另请注意我们编写的三条日志消息的时间戳(它们不会出现在代码段控制台中,直到macrotask显示它们,但时间戳显示我们何时记录它们。)
所以基本上,你可以安排一堆微任务,并定期让它们用完并运行下一个macrotask。
注意:我在代码段中使用了setInterval
作为浏览器示例,但setInterval
对于使用NodeJS的类似实验可能不是一个好的选择,因为NodeJS的setInterval
与浏览器中的<div id="slider"></div>
<input type="number" id="firstInput">
<input type="number" id="secondInput">
略有不同,并且具有一些令人惊讶的时序特征。
答案 1 :(得分:0)
有些lib可以像cron任务一样工作,例如https://www.npmjs.com/package/node-cron
我认为使用cron应该更容易,更灵活。