(我需要在浏览器上有一个 process.nextTick 等效项。)
我试图充分利用 javascript 性能,所以我做了一个简单的计数器...... 一秒钟后,我连续调用一个函数,该函数仅向变量加一。
代码:codepen.io/rafaelcastrocouto/pen/gDFxt
我在 google chrome / win7 中使用 setTimeout 得到了大约 250 个,使用 requestAnimationFrame 得到了 70 个。 我知道 requestAnimationFrame 与屏幕刷新率相关,那么我们如何才能使其更快?
PS:我知道asm.js
setImmediate()
可以立即运行代码,即正如您所期望的 setTimeout(0)
那样。
不同之处在于
setTimeout(0)
实际上并不立即运行; setTimeout
被“限制”为最短等待时间(4 毫秒),这就是为什么您在测试程序中只能得到 250 的计数。 setImmediate()
确实会立即运行,因此使用它您的计数器测试将会提高几个数量级。
但是,您可能想检查浏览器对
setImmediate
的支持——它尚未在所有浏览器中可用。 (当然,您可以使用 setTimeout(0)
作为后备,但随后您又回到了它所规定的最短等待时间)。
postMessage()
也是一个选项,并且可以实现大致相同的结果,尽管它是一个更复杂的 API,因为它的目的不仅仅是简单的调用循环。另外,使用它时还需要考虑其他注意事项(有关更多信息,请参阅链接的 MDN 文章)。
setImmediate
的 polyfill 库,它使用 postMessage
和其他技术将 setImmediate
添加到尚不支持它的浏览器中。
使用
requestAnimationFrame()
,您的测试程序应该得到 60,因为这是每秒的标准帧数。如果您获得的时间超过这个值,那么您的程序运行的时间可能超过一秒。
使用它在计数测试中永远不会得到很高的数字,因为它每秒仅触发 60 次(如果硬件刷新帧速率由于某种原因较低,则触发次数更少),但如果您的任务涉及更新display 那么这就是您所需要的,因此您可以使用
requestAnimationFrame()
来限制调用它的次数,从而为程序中的其他任务释放资源。
这就是
requestAnimationFrame()
存在的原因。如果您关心的只是让代码尽可能频繁地运行,那么就不要使用 requestAnimationFrame()
;请使用 setTimeout
或 setImmediate
代替。但这不一定是性能最好的事情,因为它会消耗浏览器执行其他任务所需的处理器能力。
最终,性能不仅仅是让某个东西运行最多次数;而是让某个东西运行最多次数。这是为了让用户体验尽可能流畅。这通常意味着对您的调用循环施加限制。
异步时最短的延迟来自
MutationObserver
,但它太短了,如果你继续调用它,UI 将永远没有机会更新。
因此,技巧是使用
MutationObserver
来增加值,同时偶尔使用 requestAnimationFrame
来更新 UI,但这是不允许的。
参见http://jsfiddle.net/6TZ9J/1/
var div = document.createElement("div");
var count = 0;
var cur = true;
var now = Date.now();
var observer = new MutationObserver(function () {
count++;
if (Date.now() - now > 1000) {
document.getElementById("count").textContent = count;
} else {
change();
}
});
observer.observe(div, {
attributes: true,
childList: true,
characterData: true
});
function change() {
cur = !cur;
div.setAttribute("class", cur);
}
change();
按照
此博客中所述使用
postMessage()
。
var timeouts = [];
var messageName = "zero-timeout-message";
// Like setTimeout, but only takes a function argument. There's
// no time argument (always zero) and no arguments (you have to
// use a closure).
function setZeroTimeout(fn) {
timeouts.push(fn);
window.postMessage(messageName, "*");
}
function handleMessage(event) {
if (event.source == window && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
window.addEventListener("message", handleMessage, true);
postMessage
现在(2023 年)拥有出色的浏览器支持。