Skip to content

Instantly share code, notes, and snippets.

@dushaobindoudou
Last active December 4, 2020 03:55
Show Gist options
  • Save dushaobindoudou/0976fd723d38162eb20014d07ea31a0d to your computer and use it in GitHub Desktop.
Save dushaobindoudou/0976fd723d38162eb20014d07ea31a0d to your computer and use it in GitHub Desktop.

requestIdleCallback 记录

requestAnimationFrame 可以规划动画,最大化60fps的机会

requestIdleCallback 当一帧结束的空闲时间或者非活动状态来调度任务,我们不妨碍用户的情况下执行任务, ie、safari不支持,safari可以手动开启

找出浏览器处于非交互状态是很难的,需要绑定很多用户事件,或者使用requestAnimationFrame来计算,使用requestIdleCallback可以明确的返回 一个用户非交互状态的回调

怎么使用

判断是否可用,如果不可用退回setTimeout

window.requestIdleCallback =
  window.requestIdleCallback ||
  function (cb) {
    var start = Date.now();
    return setTimeout(function () {
      cb({
        didTimeout: false,
        timeRemaining: function () {
          return Math.max(0, 50 - (Date.now() - start));
        }
      });
    }, 1);
  }

window.cancelIdleCallback =
  window.cancelIdleCallback ||
  function (id) {
    clearTimeout(id);
  }

调用

requestIdleCallback((deadLine) => {
  
});

deadLine 包含一个函数timeRemaining, 他会告诉你是否还有剩余时间可用

如果 timeRemaining 返回零 表明已经没有闲置时间了,你需要等待下一次调用

如果浏览器非常繁忙,requestIdleCallback 可能很长一段时间都不会调用,这种情况可以添加第二个参数 {timeout: 2000} 毫秒数, 会保证 过期后强制调用,如果timeout被调用 didTimeout 属性会返回true

使用 requestIdleCallback 发送统计数据

如果用户点击的时候,你可能不希望立即发送统计数据,可以使用 requestIdleCallback 保证用户始终可用

function schedulePendingEvents() {

  // Only schedule the rIC if one has not already been set.
  if (isRequestIdleCallbackScheduled)
    return;

  isRequestIdleCallbackScheduled = true;

  if ('requestIdleCallback' in window) {
    // Wait at most two seconds before processing events.
    requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 });
  } else {
    processPendingAnalyticsEvents();
  }
}

function processPendingAnalyticsEvents (deadline) {

  // Reset the boolean so future rICs can be set.
  isRequestIdleCallbackScheduled = false;

  // If there is no deadline, just run as long as necessary.
  // This will be the case if requestIdleCallback doesn’t exist.
  if (typeof deadline === 'undefined')
    deadline = { timeRemaining: function () { return Number.MAX_VALUE } };

  // Go for as long as there is time remaining and work to do.
  while (deadline.timeRemaining() > 0 && eventsToSend.length > 0) {
    var evt = eventsToSend.pop();

    ga('send', 'event',
        evt.category,
        evt.action,
        evt.label,
        evt.value);
        
  }

  // Check if there are more events still to send.
  if (eventsToSend.length > 0)
    schedulePendingEvents();
}

再页面布局后操作

frame图

避免中 requestIdleCallback 修改dom元素

如果 requestIdleCallback 在当前帧末尾触发,也就意味着在元素更新,布局重新计算之后进行, 也就是提交之后执行,在 requestIdleCallback 之内 进行布局计算就是不合法的,如果 getBoundingClientRect, clientWidth 属性在下一帧被读取,就会触发浏览器强制同步布局,会导致性能瓶颈

另外一个原因是 不建议在 requestIdelCallback 改变样式,会导致不可预期的结果,并且很容易超出浏览器的给的deadline

dom元素更改最好在requestAnimationFrame中进行,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment