Hello, everyone. I am Karsong.

React’s concurrency model, which has been perfected for several years, consists of the following two parts:

  • Interruptible update architecture based on Fiber implementation

  • Scheduler based priority scheduling

Most of the React team’s work has been around these two things since fiber was reimagined in 2016 until the official release of Act 18 later this year (or early next year).

Wouldn’t it be surprising to tell you that the priority scheduling that React worked so hard to implement is now supported by browsers natively?

Building a Faster Web Experience with the postTask Scheduler

What is priority scheduling

Suppose we have a logging script that needs to be executed after the page is initialized:

initCriticalTracking();
Copy the code

The call stack torch diagram is as follows:

As you can see, this was a long task that took 249.08ms, during which the browser dropped frames (browser stuttering).

Now we wrap it in the callback function of the priority scheduler function scheduler.postTask:

scheduler.postTask(() = > initCriticalTracking());
Copy the code

Long tasks are broken down into short tasks:

The browser has the opportunity to rearrange and redraw between each task, reducing the possibility of dropping frames.

Priority scheduling is the technique of disassembling tasks and allocating execution time according to task priority.

Scheduler. postTask is a priority scheduling API implemented by Chrome.

Scheduler. postTask is an experimental feature, which requires #enable-experimental-web-platform-features in Chrome ://flags

How was priority scheduling implemented previously

Prior to scheduler.postTask, priority scheduling was usually simulated using browser-provided apis that were called at various stages, such as:

  • RequestAnimationFrame (rAF for short) is typically used to process animations and is triggered before the browser renders

  • RequestIdleCallback (rIC for short) is called at idle time in each frame when there are no other tasks

  • SetTimeout, postMessage, and MessageChannel fire between renders

React uses MessageChannel for priority scheduling and setTimeout for demotion.

However, these apis do their job. The priority scheduling implemented with them is crude.

For this reason, the postTask Scheduler was born.

Use of the postTask Scheduler

Scheduler.posttask has three priorities:

priority describe Polyfill implementation
user-blocking Highest priority, which may block user interaction MessageChannel is used to schedule tasks and setTimeout is used as the demotion scheme
user-visible Second priority, visible to the user but not blocking user interaction. For example: Render second screen content. This is the default priority Control via priority queue based on user-blocking implementation
background Lowest priority, usually performing non-urgent tasks, such as logging Use rIC implementation, setTimeout(0) as the downgrade scheme

The usage is simple. Callback functions registered with the following method are scheduled with the default priority:

// Default priority
scheduler.postTask(() = > console.log('Hello, postTask'));
Copy the code

You can also specify priorities and execution delays:

// The invocation is delayed by 1 second, and has the lowest priority
scheduler.postTask(() = > console.log('Hello, postTask'), {
   delay: 1000.priority: 'background'});Copy the code

PostTask is built on the AbortSignal API, so we can cancel callback functions that are queued and not yet executed.

By using the TaskController API:

const controller = new TaskController('background');
window.addEventListener('beforeunload'.() = > controller.abort());
 
scheduler.postTask(() = > console.log('Hello, postTask'), {
   signal: controller.signal,
});
Copy the code

Meanwhile, the experimental schedule.wait method makes it easy to wait for a certain time before performing tasks.

For example, we can asynchronously load xxx.js after the page has finished loading:

async function loadxxx() {
  // Wait for the event to be dispatched
  await scheduler.wait('myPageHasLoaded');
  return import('xxx.js');
}
 
// Send events after the page loads
window.dispatchEvent(new CustomEvent('myPageHasLoaded'));
Copy the code

The above code is simplified to the postTask event configuration item:

scheduler.postTask(() = > import('xxx.js'), {
   event: 'myPageHasLoaded'
})
Copy the code

conclusion

Priority scheduling can be used in many areas, such as:

  • Resource requests are advanced and deferred

  • Third-party resources are loaded lazily

.

Predictably, this will increase front-end programming complexity in the future.

Once upon a time, when Web applications became complex enough, front-end frameworks emerged so that developers didn’t have to manipulate the DOM directly.

In the future, when priority scheduling becomes complex enough, there will certainly be integrated solutions that allow developers to manipulate priorities without having to do so directly.

Wait, isn’t that what React is doing right now?

Welcome to join the Human high quality front-end framework research group, Band fly