浏览器读取并运行一个JavaScript文件,写入该文件的同步任务立即变为执行中任务,setTimeout回调变为宏任务,并保证回调变为微任务。一切都很好。
我以为我掌握了JavaScript事件循环,直到遇到requestAnimationFrame
。
@ T.J。 Crowder为我提供了以下代码段。
const messages = [];
setTimeout(() => {
// Schedule a microtask
Promise.resolve().then(() => {
log("microtask");
});
// Schedule animation frame callback
requestAnimationFrame(() => {
log("requestAnimationFrame");
});
// Schedule a macrotask
setTimeout(() => {
log("macrotask");
}, 0);
// Schedule a callback to dump the messages
setTimeout(() => {
messages.forEach(msg => {
console.log(msg);
});
}, 200);
// Busy-wait for a 10th of a second; the browser will be eager to repaint when this task completes
const stop = Date.now() + 100;
while (Date.now() < stop) {
}
}, 100);
function log(msg) {
messages.push(Date.now() + ": " + msg);
}
规范没有说明这是否可以在宏任务完成与计划微任务处理之间发生,还是只能在宏任务之间发生。因此,可能会因浏览器而异。
但是在Chrome和Firefox中,微任务总是在requestAnimationFrame
回调之前执行。我的以下问题基于此观察。
** Q1:**
即使浏览器没有重画工作,requestAnimationFrame的回调是否将以刷新率(默认为每秒60个)执行?
** Q2:**
下面来自https://developers.google.com/web/fundamentals/performance/rendering/debounce-your-input-handlers
确保JavaScript在帧的开头运行的唯一方法是使用
requestAnimationFrame
。
过于繁重的中间执行任务将滞后于浏览器,导致帧间隔超过16.66ms,阻止帧完成。
'保证'一词是否意味着微任务将在当前JS堆栈变空后立即执行中,从而阻止当前帧完成(如果微任务也太重)?
The spec并没有说这是否可以在宏任务完成与计划微任务处理之间发生,还是仅在宏任务之间发生。因此大概会因浏览器而异。
[The old spec(现在已过时且已取代)用宏任务的术语描述了它,暗示它应该在宏任务之间,但是事情可能已经从那里移了。
执行最早的任务(宏任务)。
requestAnimationFrame
回调const messages = [];
setTimeout(() => {
// Schedule a microtask
Promise.resolve().then(() => {
log("microtask");
});
// Schedule animation frame callback
requestAnimationFrame(() => {
log("requestAnimationFrame");
});
// Schedule a macrotask
setTimeout(() => {
log("macrotask");
}, 0);
// Schedule a callback to dump the messages
setTimeout(() => {
messages.forEach(msg => {
console.log(msg);
});
}, 200);
// Busy-wait for a 10th of a second; the browser will be eager to repaint when this task completes
const stop = Date.now() + 100;
while (Date.now() < stop) {
}
}, 100);
function log(msg) {
messages.push(Date.now() + ": " + msg);
}