三羊

三羊的小站

React Time Slice(三) - requestIdleCallback polyfill

November 15, 2020/「 reacttime slice / Edit on Github ✏️

还记得我们在第一篇中说过,当前rIC实现版本有一条不足之处,当浏览器切换到其他tab或者后台时,浏览器会出于优化考虑不执行rAF(可查看Background Tabs in Chrome),而 rIC polyfill 的实现依赖rAF的实现,所以rIC也会得不到执行。

Fallback to setTimeout

为了解决这种场景下的问题,React v16.5.0 中使用setTimeout来作为兜底,100ms内,如果rAF没有执行,则使用setTimeout来触发执行,实现大致如下,

const animationFrameTimeout = 100;
let rafID;
let timeoutID;
const scheduleAnimationFrameWithFallbackSupport = function(callback) {
  // schedule rAF and also a setTimeout
  rafID = requestAnimationFrame(function(timestamp) {
    // cancel the setTimeout
    clearTimeout(timeoutID);
    callback(timestamp);
  });
  timeoutID = setTimeout(function() {
    // cancel the requestAnimationFrame
    cancelAnimationFrame(rafID);
    callback(now());
  }, animationFrameTimeout);
};

如果浏览器在切换到其他tab或者后台时,限制了rAF的执行,会不会也限制setTimeout的执行,rIC会不会也同样本身也会被限制呢?据MDN上的文档说明,setTimeout同样也会被限制,

Timeouts in inactive tabs throttled to ≥ 1000ms

To reduce the load (and associated battery usage) from background tabs, timeouts are throttled to firing no more often than once per second (1,000 ms) in inactive tabs.

Firefox implements this behavior since version 5 (see bug 633421, the 1000ms constant can be tweaked through the dom.min_background_timeout_value preference). Chrome implements this behavior since version 11 (crbug.com/66078).

Firefox for Android uses a timeout value of 15 minutes for background tabs since bug 736602 in Firefox 14, and background tabs can also be unloaded entirely.

w3c文档说明,rIC同样也可能会被限制

When the user agent determines that the web page is not user visible it can throttle idle periods to reduce the power usage of the device, for example, only triggering an idle period every 10 seconds rather than continuously.

那既然对于inactive tab 这种情况,setTimeout,rIC本身都会被限制执行,上面React v16.5.0中 使用setTimeout来作为回退就没有什么意义了。如果哪位同学知道还有其他方面的原因,还请联系告诉我。

资料

  1. Fall back to ‘setTimeout’ when ‘requestAnimationFrame’ is not called
  2. Background Tabs in Chrome

若有收获,小额鼓励