gpt4 book ai didi

javascript - requestAnimationFrame 什么时候执行?

转载 作者:可可西里 更新时间:2023-11-01 02:45:20 26 4
gpt4 key购买 nike

浏览器读取并运行一个 JavaScript 文件,文件中写入的同步任务立即成为 in-mid-execution 任务,setTimeout 回调成为宏任务,promise 回调成为微任务。一切都很好。

在遇到 requestAnimationFrame 之前,我以为我掌握了 JavaScript 事件循环。

@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:微任务、requestAnimationFrame、宏任务
  • Firefox:微任务、宏任务、requestAnimationFrame

规范没有说明这是否可以发生在宏任务完成和它的预定微任务处理之间,或者只发生在宏任务之间。所以大概这会因浏览器而异。

但是在 Chrome 和 Firefox 中,微任务总是在 requestAnimationFrame 回调之前执行。我的以下问题是基于这一观察。


**Q1:**

即使浏览器没有重绘工作,requestAnimationFrame 的回调是否会以刷新率(默认每秒 60 次)执行?


**Q2:**

以下来自https://developers.google.com/web/fundamentals/performance/rendering/debounce-your-input-handlers

The only way to guarantee that your JavaScript will run at the start of a frame is to use requestAnimationFrame.

太重的in-mid-execution任务会导致浏览器滞后,导致帧间隔超过16.66ms,阻塞帧完成。

“保证”一词是否意味着微任务将在当前 JS 堆栈变空时立即执行,从而阻止当前帧完成(如果微任务也太重)?

最佳答案

它基本上是它自己的东西。当浏览器要重绘页面时,如果没有被正在运行的任务阻塞,它通常每秒重绘 60 次,它会在重绘之前调用所有排队的 requestAnimationFrame 回调,然后重绘.

The spec没有说明这是否会发生在任务(宏任务)的完成和它的预定微任务的处理之间,或者只发生在(宏)任务之间。所以大概这会因浏览器而异。

The old spec (现已过时和取代)用(宏观)任务术语描述它,暗示它将在(宏观)任务之间,但事情可能已经从那里开始。

规范现在说明何时在 Event Loop Processing Model 中发生这种情况部分。删除了很多细节的简化版本是:

  1. 做最早的(宏)任务
  2. 做微任务
  3. 如果这是渲染的好时机:
    1. 做一些准备工作
    2. 运行requestAnimationFrame回调
    3. 渲染

我们来做个测试:

const messages = [];
setTimeout(() => {
// Schedule a microtask
Promise.resolve().then(() => {
log("microtask");
});

// Schedule animation frame callback
requestAnimationFrame(() => {
log("requestAnimationFrame");
});

// Schedule a (macro)task
setTimeout(() => {
log("(macro)task");
}, 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:微任务、requestAnimationFrame、(宏)任务
  • Firefox:微任务、(宏)任务、requestAnimationFrame

(我在这些浏览器上反复测试可靠地得到了相同的结果。我手边没有 Edge...)

现在 Chrome(可能还有 Chromium、Brave 和新的 Edge)、Firefox、iOS Safari 和 Legacy Edge 都做同样的事情,符合规范:微任务、requestAnimationFrame、(宏)任务。

这是一个忙等待预先的版本,而不是最后,以防它改变某些东西:

const messages = [];
setTimeout(() => {
// 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) {
}

// Schedule a microtask
Promise.resolve().then(() => {
log("microtask");
});

// Schedule animation frame callback
requestAnimationFrame(() => {
log("requestAnimationFrame");
});

// Schedule a (macro)task
setTimeout(() => {
log("(macro)task");
}, 0);

// Schedule a callback to dump the messages
setTimeout(() => {
messages.forEach(msg => {
console.log(msg);
});
}, 200);

}, 100);

function log(msg) {
messages.push(Date.now() + ": " + msg);
}

通过该更改,我在 Chrome 和 Firefox 上可靠地获得了微任务、requestAnimationFrame、(宏)任务。我现在得到的结果与前面的代码片段相同。


**Q1: **

Even though the browser has no repaint work, the requestAnimationFrame's callback will be excuted at the refresh rate (default 60 per second).

前提是没有任何阻塞。

**Q2: **

这句话的意思完全且仅是它所说的:您的回调将在绘制帧之前立即被调用(连同任何排队的 requestAnimationFrame 回调)。这并不意味着必须每 60 秒绘制一帧 — 因为线程可能正忙于做其他事情。

这些回调不会中断其他任务。再次声明:如果其他任务让主 UI 线程忙,那么它很忙,并且帧速率会受到影响。

关于javascript - requestAnimationFrame 什么时候执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43050448/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com