RequestIdleCallback () inserts a function that will be called when the browser is idle. Enables developers to perform background and low-priority work on the main event loop without affecting the delay of critical events such as animations and input responses.
API
const handle = window.requestIdleCallback(callback[, options])
Copy the code
callback
The: callback, which is a task that needs to be performed when idle, accepts oneIdleRequestCallback
Object as a parameter.IdleRequestCallback
Objects include:didTimeout
: Boolean value that indicates whether the task times outtimeRemaining
usetimeRemaining
: Indicates the remaining time of the current frame
options
: Currently, only one parameter is availabletimeout
: indicates that the task is forcibly executed if the task has not been executed after the specified time
Example:
requestIdleCallback(myNonEssentialWork);
function myNonEssentialWork(deadline) {
// deadline.timeremaining () retrieves the remaining time of the current frame
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
doWorkIfNeeded();
}
if (tasks.length > 0) { requestIdleCallback(myNonEssentialWork); }}Copy the code
Difference between requestIdleCallback and requestAnimationFrame
The requestAnimationFrame callback is confirmed every frame and is a high priority task. The callback to requestIdleCallback is not necessarily a low-priority task.
The page we see is drawn frame-by-frame by the browser, and FPS is usually smooth at 60, while FPS is slow at low FPS.
So what does the browser do in each frame, as shown below:
One frame includes user interaction, JavaScript script execution; RequestAnimationFrame (rAF) calls, layout calculations, page redrawing, etc.
If a frame does not perform a lot of tasks and the above tasks are completed in less than 16.66ms(1000/60), then the frame will have some free time to execute the requestIdleCallback callback, as shown in the figure below:
When the application stack is empty and the browser is idle, the time allowed for requestIdleCallback execution can be appropriately extended, up to 50ms, to prevent unpredictable tasks (such as user input) and avoid delays perceived by users when they cannot respond in a timely manner.
Since requestIdleCallback takes advantage of the frame’s idle time, it is possible that the browser is always busy and the callback cannot be executed. In this case, you need to pass the second configuration parameter timeout when calling requestIdleCallback.
requestIdleCallback(myNonEssentialWork, { timeout: 2000 });
function myNonEssentialWork(deadline) {
Deadline. didTimeout is true if the callback is executed because of a timeout
while (
(deadline.timeRemaining() > 0 || deadline.didTimeout) &&
tasks.length > 0
) {
doWorkIfNeeded();
}
if (tasks.length > 0) { requestIdleCallback(myNonEssentialWork); }}Copy the code
If the timeout callback is executed, the user may feel stuck because a frame is longer than 16ms.
RequestIdleCallback performs DOM modification operations
It is strongly recommended not to perform DOM modification operations in requestIdleCallback.
As you can see from the composition of the above frame, the style changes, layout calculations, and so on are completed before the requestIdleCallback callback is executed. If you modify the DOM in the callback, the previous layout calculation is invalidated. And if there are operations related to retrieving the layout in the next frame, the browser will have to force a rearrangement, which can have a significant impact on performance. In addition, because the time to modify the DOM is unpredictable, it is easy to exceed the current frame free threshold.
The recommended approach is to make DOM changes in the requestAnimationFrame.
In addition to DOM modification not being recommended, Promise’s resolve(Reject) operation is also not recommended because Promise’s callback executes immediately after Idle’s callback completes, lengthening the current frame.
Example: Use requestIdleCallback to report data
In some cases, we want to be able to track an event, such as “click the navigation bar menu “. We will create an array of events to delay reporting and avoid sending events immediately.
var eventsToSend = [];
function onNavOpenClick() {
// Animate the menu.
menu.classList.add("open");
// Store the event for later.
eventsToSend.push({
category: "button".action: "click".label: "nav".value: "open"}); schedulePendingEvents(); }Copy the code
Use requestIdleCallback to handle pending events:
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(); }}Copy the code
The callback method executed by requestIdleCallback:
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();
}
Copy the code
reference
build your own react
You should know about requestIdleCallback
Using requestIdleCallback
MDN – requestIdleCallback