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 保证用户始终可用
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();
}
如果 requestIdleCallback 在当前帧末尾触发,也就意味着在元素更新,布局重新计算之后进行, 也就是提交之后执行,在 requestIdleCallback 之内 进行布局计算就是不合法的,如果 getBoundingClientRect, clientWidth 属性在下一帧被读取,就会触发浏览器强制同步布局,会导致性能瓶颈
另外一个原因是 不建议在 requestIdelCallback 改变样式,会导致不可预期的结果,并且很容易超出浏览器的给的deadline
dom元素更改最好在requestAnimationFrame中进行,