We all know React 16 implements a new scheduling policy (Fiber). The new asynchronous and interruptible scheduling policy is based on the browser-based requestIdleCallback and requestAnimationFrame apis. React implements a similar requestIdleCallback mechanism on its own, but it’s not much different, so it’s worth looking at both apis.

What is a requestIdleCallback?

RequestIdleCallback should be used when you are concerned about user experience and don’t want users to feel stuck on unimportant tasks such as reporting statistics. The requestIdleCallback callback is executed only if the current browser is idle.

requestIdleCallback will schedule work when there is free time at the end of a frame, or when the user is inactive.

RequestIdleCallback Usage example

    requestIdelCallback(myNonEssentialWork);
    
    
    functionMyNonEssentialWork (deadline) {// deadline.timeremaining () obtains the remaining time of the current framewhile (deadline.timeRemaining() > 0 && tasks.length > 0) {
        doWorkIfNeeded();
      }
      if(tasks.length > 0){ requestIdleCallback(myNonEssentialWork); }}Copy the code

What is the difference between requestIdleCallback and requestAnimationFrame?

RequestAnimationFrame callbacks are executed on each frame and are high priority tasks, while requestIdleCallback callbacks are not necessarily low priority tasks. The web is drawn frame by frame in the browser. A FPS of 60 is generally considered to be smooth, while a single-digit FPS is considered to be the user’s perception of a lag. So what does the browser do in a frame?

The frame contains user interaction, JS execution, requestAnimationFrame invocation, layout calculation, and page redrawing. If there are few tasks to perform in a frame and the tasks are completed in less than 16ms (1000/60), the frame will have a certain amount of idle time, which can be used to perform the requestIdleCallback callback, as shown below:

When the stack is empty and the browser is actually idle, the time for requestIdleCallback to execute can be extended, up to 50ms, to prevent user-perceived delays caused by an unpredictable task (user input).

Since requestIdleCallback takes advantage of the frame’s idle time, it is possible that the browser is always busy and the callback will never execute, which is not the desired result (such as a lost report). So in this case we need to pass the second configuration parameter timeout when we call requestIdleCallback?

requestIdleCallback(myNonEssentialWork, { timeout: 2000 });

functionMyNonEssentialWork (deadline) {// if the callback function is executed due to a timeout, deadline.didTimeout istrue
  while ((deadline.timeRemaining() > 0 || deadline.didTimeout) &&
         tasks.length > 0) {
       doWorkIfNeeded();
    }
  if(tasks.length > 0) { requestIdleCallback(myNonEssentialWork); }}Copy the code

If the timeout callback is the reason for the execution, the user will probably feel the delay, because the execution time of a frame must have exceeded 16ms

Can DOM modification be performed in requestIdleCallback?

It is highly recommended not to. As you can see from the composition of the frame above, the implementation of the requestIdleCallback callback indicates that the previous work (including the style change and layout calculation) has been done. If we make DOM changes in the callback, all previous layout calculations will be invalid, and the browser will have to perform a forced reorder if the next frame has a layout operation (such as getBoundingClientRect, clientWidth), which will have a significant performance impact. In addition, because the time to modify the DOM operation is unpredictable, it is easy to exceed the current frame idle time threshold, so it is not recommended. The recommended approach is to make dom changes in requestAnimationFrame. You can build a Document Fragment in requestIdleCallback. Then apply the Fragment to the requestAnimationFrame in the next frame.

In addition to DOM modification, a Promise’s resolve operation is not recommended, because the Promise’s callback will be executed immediately after the IDLE callback has completed, lengthening the frame time.

It is recommended that the tasks in requestIdleCallback be small and predictable tasks. For more information about microTask, see here

RequestIdleCallback Compatibility

The NPM package request-idle-callback is recommended

The resources

Developers.google.com/web/updates… medium.com/@paul_irish… Juejin. Im/entry / 68449… Insights. Thoughtworks. Cn/react – fiber…