requestAnimationFrame何时执行? [英] When will requestAnimationFrame be executed?

查看:79
本文介绍了requestAnimationFrame何时执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

浏览器读取并运行JavaScript文件,文件中写入的同步任务立即变为执行中任务,setTimeout回调变为macrotasks,并且promise回调变为微任务。一切都很好。

Browser reads and runs a JavaScript file, the synchronous tasks written in the file immediately become in-mid-execution task, setTimeout callbacks become macrotasks, and promise callbacks become microtasks. Everything is good.

我认为我已经掌握了JavaScript事件循环,直到遇到 requestAnimationFrame

I thought I mastered the JavaScript Event Loop until I met requestAnimationFrame.

@TJ Crowder为我提供了以下代码片段。

@T.J. Crowder provided me with the following code snippet.

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:microtask,requestAnimationFrame,macrotask

  • Firefox:microtask,macrotask,requestAnimationFrame

规范没有说明在完成宏任务和处理其预定的微任务之间是否会发生这种情况,或者只是在macrotasks之间。所以可能是浏览器与浏览器不同。

The spec doesn't say whether that can happen between the completion of a macrotask and the processing of its scheduled microtasks, or only between macrotasks. So presumably that can vary browser to browser.

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

But in both Chrome and Firefox, microtasks are always executed before requestAnimationFrame callbacks. My questions below are based on this observation.

** Q1:**

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

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

** Q2:**

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


保证JavaScript在帧开始运行的唯一方法是使用 requestAnimationFrame

执行中任务太重将导致浏览器延迟,导致帧间隔超过16.66ms,阻止帧从完成。

Too heavy in-mid-execution task will lag the browser, cause the frame interval exceed 16.66ms, block frames from completing.

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

Does the word 'guarantee' mean that the microtasks will be in-mid-execution immediately the current JS stack becomes empty, hence block the current frame from completing (if the microtask is also too heavy)?

推荐答案

这基本上是它自己的事情。当浏览器即将重新绘制页面时,如果没有被正在运行的任务阻止,它通常会执行60次/秒,它会在执行此操作之前调用所有排队的 requestAnimationFrame 回调,然后进行重新绘制。

It's basically its own thing. When the browser is about to repaint the page, which it does typically 60 times/second if not blocked by a running task, it will call all queued requestAnimationFrame callbacks just before doing so, and then do the repaint.

规范没有说明在完成宏任务和处理其预定的微任务之间,还是仅在macrotasks之间发生这种情况。所以大概可以改变浏览器到浏览器。

The spec doesn't say whether that can happen between the completion of a macrotask and the processing of its scheduled microtasks, or only between macrotasks. So presumably that can vary browser to browser.

旧的规范(现在过时和取代)用macrotask术语描述它,暗示它将在macrotask之间,但事情可能已经从那里开始。

The old spec (now obsolete and superceded) described it in macrotask terms, suggesting it would be between macrotasks, but things may have moved on from there.

让我们做一个测试:

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);
}

果然,结果因浏览器而异:

Sure enough, the results vary by browser:


  • Chrome :microtask,requestAnimationFrame,macrotask

  • Firefox :microtask,macrotask,requestAnimationFrame

  • Chrome: microtask, requestAnimationFrame, macrotask
  • Firefox: microtask, macrotask, requestAnimationFrame

(我在这些浏览器上重复测试时可靠得到相同的结果。我没有Edge方便......)

(I reliably get the same results in repeated tests on those browsers. I don't have Edge handy...)

这是一个繁忙等待预先的版本,而不是最后一个版本,以防它发生变化:

Here's a version with the busy-wait up front, instead of at the end, in case it changes something:

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 macrotask
  setTimeout(() => {
    log("macrotask");
  }, 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上获得microtask,requestAnimationFrame,macrotask。

I reliably get microtask, requestAnimationFrame, macrotask on both Chrome and Firefox with that change.


** Q1:**

**Q1: **

即使浏览器没有重绘工作, requestAnimationFrame 的回调将以刷新率(默认每秒60次)为准。

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

如果没有任何阻止。


** Q2:**

**Q2: **

这句话表示完全,仅表示它的内容:在绘制帧之前,将立即调用您的回调(以及排队的任何 requestAnimationFrame 回调)。 意味着框架必须每隔60秒绘制一次 —因为线程可能正忙于做其他事情。

That sentence means exactly, and only, what it says: Your callback will be called (along with any requestAnimationFrame callbacks that are queued up) immediately prior to drawing a frame. It doesn't mean that a frame is necessarily drawn every 60th of a second — because the thread may be busy doing other things.

那些回调不会中断其他任务。再说一遍:如果其他任务的主UI线程忙,那么它很忙,帧速率也会受到影响。

Those callbacks will not interrupt other tasks. Again: If other tasks have the main UI thread busy, it's busy, and the framerate suffers.

这篇关于requestAnimationFrame何时执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆