13
头图

Hi everyone, I'm Kasong.

React recent years has been the perfect concurrent mode mainly consists of two parts:

  • Interruptible update architecture based on fiber
  • Priority scheduling based on scheduler

It can be said that from the restructuring of fiber React18 release of the official version of 06153cfbac4913 at the end of this year (or early next year) React team was carried out around these two points.

If I tell you now that priority scheduling React painstakingly for many years is natively supported by the browser, wouldn’t you be surprised?

The article refers to 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();

The call stack torch diagram is as follows:

It can be seen that this is a long task that has been executed for 249.08ms, and the browser will drop frames during execution (shown as browser freeze).

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

scheduler.postTask(() => initCriticalTracking());

The long task is broken down into multiple short tasks:

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

This disassembles tasks according to task priority and allocates execution time to the technology , which is priority scheduling .

scheduler.postTask is Chrome achieved priority scheduling API .

scheduler.postTask is an experimental feature, you need to open #enable-experimental-web-platform-features in chrome://flags

How to implement priority scheduling before

scheduler.postTask , which is usually called at different stages using the 16153cfbac4adb provided by the browser, was used to simulate priority scheduling , such as:

  • requestAnimationFrame (abbreviated as rAF ) is generally used to process animation and will be triggered before the browser is rendered
  • requestIdleCallback (abbreviated as rIC ) is called in idle time when there is no other task in each frame
  • setTimeout , postMessage , MessageChannel trigger between renderings

React uses MessageChannel implement priority scheduling, and setTimeout as the downgrading scheme.

However, these API all have their own jobs after all. Using their priority scheduling relatively rough.

For this reason, postTask Scheduler born.

Use of postTask Scheduler

scheduler.postTask has 3 optional priority levels:

prioritydescribepolyfill implementation
user-blockingHighest priority, may block user interactionUse MessageChannel to schedule tasks, setTimeout as a downgrade scheme
user-visibleThe second priority is visible to users, but does not block user interaction. For example: rendering the content of the second screen. This is the default priorityControlled by priority queue based on user-blocking implementation
backgroundLowest priority, usually perform non-urgent tasks, such as loggingUse rIC implementation, setTimeout(0) as a downgrade scheme

The usage is very simple. The callback function registered in the following way will be default priority of :

// 默认优先级
scheduler.postTask(() => console.log('Hello, postTask'));

You can also specify the priority and execution delay:

// 调用后延迟1秒执行,优先级最低
scheduler.postTask(() => console.log('Hello, postTask'), {
   delay: 1000,
   priority: 'background',
});

postTask built on AbortSignal API , so we can cancel callback functions that are still in the queue and have not been executed.

By using TaskController API control:

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

At the same time, the experimental schedule.wait method allows us to easily wait for a certain time before performing the task.

For example, we can asynchronously load xxx.js after the page is loaded:

async function loadxxx() {
  // 等待事件被派发
  await scheduler.wait('myPageHasLoaded');
  return import('xxx.js');
}
 
// 页面加载后派发事件
window.dispatchEvent(new CustomEvent('myPageHasLoaded'));

The above code is simplified postTask of event configuration items:

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

Summarize

priority scheduling can be applied in many fields, such as:

  • Resource advance and postponement request
  • Lazy loading of third-party resources

......

It is foreseeable that this will inevitably increase the complexity of front-end programming in the future.

Just as before, when the web complicated to a certain extent, a front-end framework appeared, and developers did not need to directly operate DOM .

In the future, when the priority scheduling complicated to a certain extent, an integrated solution will surely appear, so that developers do not need to directly manipulate the priority.

React minute, isn't this what 06153cfbac4f1d is doing now?

Welcome to join the human high-quality front-end framework research group , lead the flight


卡颂
3.1k 声望16.7k 粉丝