RequestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame

React Fiber scheduling

React V16 uses Fiber instead of Stack. Fiber has the following advantages over Stack:

  • Ability to slice interruptible tasks.
  • Ability to adjust priorities, reset and reuse tasks.
  • The ability to interleave parent and child elements to support layout in React.
  • In therender()To return multiple elements.
  • Better support for error boundaries.

The main implementation of Fiber scheduling actually references two of the interesting API implementations in the BOM: requestIdleCallback and requestAnimationFrame. React hacks these two apis are native to the BOM. React hacks its own API (essentially the same).

Browser frames

In the working mechanism of the browser, there will be a frame drawing process at the end, and the web page that the user sees is actually drawn frame by frame by browser. When the FPS (the number of frames drawn per second) reaches 60, it will appear smooth to the human eye, but if the FPS is less than 60, If you’ve played LOL or DOTA, you’ll be familiar with FPS and frame loss.

So how long should a frame be drawn for smooth results?

1000/60 ≈ 16ms, 16ms.

So what does the browser do in this frame?

As you can see, each frame does the following:

  • The user interaction
  • JS parsing execution
  • Frame start: includes window resizing, scrolling, animation, etc
  • RAF: containsrequestAnimationFrameEtc.
  • layout
  • draw

As you can see, rAF is a fixed step in the process of completing each frame, so requestAnimationFrame must be executed on each frame.

requestAnimationFrame

window.requestAnimationFrame(callback);
Copy the code
  • Callback: The function called to update the animation frame before the next redraw
  • Returns a long integer, can be used in the window. The cancelAnimationFrame () to cancel the callback function

It is up to the system to decide when to execute the callback function, which is requested by the browser before the next rendering. Regardless of the refresh rate of the device, the requestAnimationFrame interval follows the time it takes to refresh the screen once; For example, if the refresh rate of a device is 75 Hz, then the time interval is 13.3 ms (1 second / 75 times).

Note that this method ensures that the callback function is rendered only once per frame, but if there are too many tasks in that frame, it will still cause a lag. So it can only guarantee that the minimum time between rerenders is the screen refresh time.

Specific use demo can be viewed: how to render tens of thousands of data not stuck interface

requestIdleCallback

16ms is the ideal value for completing a frame, so if 16ms is not consumed at the end of a frame, such as 4ms, 10ms, then the browser will choose to execute tasks in the requestIdleCallback during the remaining free time.

Of course, requestIdleCallback is not executed if there is no free time.

Specific use is as follows:

var handle = window.requestIdleCallback(callback[, options])
Copy the code
  • Callback: a function called at idle time, receiving oneIdleDeadLineParameter to get the current idle time and the status of whether the callback has been executed before the timeout.
  • Option: Configures the timeout parameter. If the task has not been executed after this time, the task will be executed in the next idle frame
requestIdleCallback(myNonEssentialWork, { timeout: 2000 });

// Task queue
const tasks = [
 () = > {
   console.log("First mission.");
 },
 () = > {
   console.log("Mission Two.");
 },
 () = > {
   console.log("Mission Three."); },];function myNonEssentialWork (deadline) {
 // If the frame has a spare time, or a timeout
 while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && tasks.length > 0) {
   work();
 }

 if (tasks.length > 0)
   requestIdleCallback(myNonEssentialWork);
 }

function work () {
 tasks.shift()();
 console.log('Perform the task');
}
Copy the code

So in terms of priorities: RequestAnimationFrame > requestIdleCallback, some lower-priority tasks can be executed using requestIdleCallback, but given that the timing of execution is limited, So the best task is quantifiable, subdivided microtasks.

Note:

  • As little as possiblerequestIdleCallbackBecause the layout of the frame is already drawn, manipulating the DOM may result in redrawing, and the previous frame may be a waste of overhead; Before I draw itrequestAnimationFrameBecause it is executed before the frame is drawn.
  • PromiseExecute as little as possible at this time, because it is too high a priority and the browser will decide that it needs to execute immediately, even if the current framerequestIdleCallbackHas run out of free time, will also continue to perform the Promise task, resulting in the frame greater than 16ms

conclusion

So when React adopted Fiber, it was able to incrementally render, prioritize, pause, stop, and reuse updates, making it smoother and more interactive.

Welcome to ac & Blog Post: React Fiber scheduling and browser frames