将 requestAnimationFrame 用于非动画目的有什么好处?

Any advantages of using requestAnimationFrame for non-animation purposes?

我制作了一个“睡眠”定时器函数,在时间用完后递归调用 requestAnimationFrame 和 returns 承诺。我为此使用 requestAnimationFrame 有什么性能优势吗?还是我应该只使用 setTimeout?我知道 requestAnimationFrame 在非常 short/quick 的等待时间(又名动画帧)上有更好的性能,但是对于接近或超过一秒的等待时间它有什么不同吗?

var sleep = (time) =>{
  var timer = (t, s, d, r)=>{
    if(t - s > d){
      r("done")
    } else {
      requestAnimationFrame((newT)=>{ timer(newT, s, d, r)})
    }
  }
  return new Promise((r)=>{
    requestAnimationFrame((t)=>{timer(t, t, time, r)})
  })
}

(async ()=>{
  var message = document.getElementById("message")
  while(message){
    message.innerText = "Get"
    await sleep(1000)
    message.innerText = message.innerText + " Ready"
    await sleep(1000)
    message.innerText = message.innerText + " To"
    await sleep(1000)
    message.innerText = message.innerText + " Wait"
    await sleep(1000)
  }
})()
<p style="text-align:center; font-size:20px;" id="message"></p>

requestAnimationFrame只是一种计时方法,顾名思义,它也request一个动画帧。

在浏览器中,event loop processing model does first execute normal tasks, and then, when the browser thinks it should update the rendering, it calls a special part of this processing model which will well, update the rendering

在大多数事件循环迭代中,不满足进入处理模型的这个可选部分所需的条件,因此不进行渲染,这很好,因为渲染成本很高。

尽管规范让实施者选择他们将使用什么启发式来决定何时应该更新渲染,但大多数人会使用监视器的 refresh-rate 作为基本频率。
除了此监视器的刷新事件之外,他们仅更新他们标记为需要更新的文档的呈现。
大多数时候,网页不需要是 re-rendered,只有当动画是 运行,或者当用户确实与之交互时,他们才会将文档标记为在需要 re-render.

requestAnimationFrame 是我们 web-devs 挂钩此更新渲染 sub-process 的工具,允许我们仅在渲染发生时绘制东西,但它也有将网页标记为 animated 的副作用,因此强制浏览器执行完整的 update the rendering 步骤,即使它可能并不需要.

例如,使用 Chrome 的性能开发工具,您可以在下面的代码片段中看到一个简单的空 rAF 循环将导致 复合层 操作得到每 screen-refresh 触发一次,而它只会在鼠标移动时发生,否则只是因为 mouse-move 在内部调用 rAF)。

const input = document.querySelector("input");
input.oninput = (evt) => {
  rAFLoop();
};
function rAFLoop() {
  if( input.checked ) {
    requestAnimationFrame( rAFLoop );
  }
}
<label><input type="checkbox" id="inp">activate rAF loop</label>

因此,虽然 requestAnimationFrame 是视觉动画的绝佳工具,但它也有责任,在您的情况下,您在滥用它。

使用简单的setTimeout才是王道,不仅不会和渲染过程有任何关系,甚至可以让浏览器idle 如果没有其他事情发生,让您的计算机执行其他任务,或者拯救树木。

const sleep = (ms) =>
  new Promise( (res) =>
    setTimeout( () => res(), ms )
  );
(async ()=>{
  var message = document.getElementById("message")
  while(message){
    message.innerText = "Get"
    await sleep(1000)
    message.innerText = message.innerText + " Ready"
    await sleep(1000)
    message.innerText = message.innerText + " To"
    await sleep(1000)
    message.innerText = message.innerText + " Wait"
    await sleep(1000)
  }
})()
<p style="text-align:center; font-size:20px;" id="message"></p>