Hi everyone, I'm Kasong.
front-end framework that merges updates triggered by multiple independent variable changes into a at one time. Different types of frameworks have different batch processing timings.
For example, the following Svelte
code, click H1
executed after onClick
callback, triggered three updates. Due to batch processing, three updates will be merged into one.
Then print the rendering results in the form of synchronization, micro task, and macro task:
<script>
let count = 0;
let dom;
const onClick = () => {
// 三次更新合并为一次
count++;
count++;
count++;
console.log("同步结果:", dom.innerText);
Promise.resolve().then(() => {
console.log("微任务结果:", dom.innerText);
});
setTimeout(() => {
console.log("宏任务结果:", dom.innerText);
});
}
</script>
<h1 bind:this={dom} on:click={onClick}>{count}</h1>
The same logic is implemented in different frameworks, and the printing results are as follows:
Vue3
: Synchronization result: 0 Micro task result: 3 Macro task result: 3Svelte
: Synchronization result: 0 Micro task result: 3 Macro task result: 3Legacy React
: Synchronization result: 0 Micro task result: 3 Macro task result: 3Concurrent React
: Synchronization result: 0 Micro task result: 0 Macro task result: 3
4 implementations ofDemo
address: React
Vue3
Svelte
The essential reason is: some frameworks use macrotasks to implement batch processing, and some frameworks use
implement batch processing.
This article will explain the macrotask and
, and their relationship with batch processing.
Welcome to join the human high-quality front-end framework group , take flight
How to schedule tasks
Put the complete flow chart first, so that you can get an overall impression:
By default, the browser (to Chrome
for example) in each Tab
corresponding to the page a rendering process, the rendering process contains the main thread, synthetic thread, IO
multiple threads and other threads.
The work of the main thread is very busy, to deal with DOM
, calculation style, processing layout, processing event response, execution JS
etc.
There are two problems to be solved here:
- These tasks not only come from within the thread, but may also come from outside. How to schedule these tasks?
- How can new tasks participate in scheduling when the main thread is working?
The answer to the first question is: message queue
All tasks participating in the scheduling will be added to the task queue. According to first in first out , the task that enters the queue first will be processed first. The pseudo code is described as follows:
// 从任务队列中取出任务
const task = taskQueue.takeTask();
// 执行任务
processTask(task);
Other processes by IPC
sends the task to the rendering process of IO
threads, IO
thread and then sent to the main thread task queue of tasks, such as:
- After the mouse is clicked, the browser process
IPC
the "click event" to theIO
thread through 06194693606243, and theIO
thread sends it to the task queue - After the resource is loaded, the network process
IPC
the "load completion event" to theIO
thread through 0619469360628d, and theIO
thread sends it to the task queue
How to schedule new tasks
The answer to the second question is: event loop
The main thread will perform tasks in the loop statement. As the cycle continues, newly added tasks will be inserted at the end of the queue, and old tasks will be taken out for execution. The pseudo code is described as follows:
// 退出事件循环的标识
let keepRunning = true;
// 主线程
function MainThread() {
// 循环执行任务
while(true) {
// 从任务队列中取出任务
const task = taskQueue.takeTask();
// 执行任务
processTask(task);
if (!keepRunning) {
break;
}
}
}
Delayed task
In addition to the task queue, the browser also WHATWG
standard to store tasks that need to be delayed (such as setTimeout
). The pseudo code is as follows:
function MainThread() {
while(true) {
const task = taskQueue.takeTask();
processTask(task);
//执行延迟队列中的任务
processDelayTask()
if (!keepRunning) {
break;
}
}
}
After the current round of cyclic tasks are executed (that is, after the execution of processTask
processDelayTask
will be executed to check whether there is a delayed task due, and if there is a task expired, it will be executed.
Between processDelayTask
execution timing in processTask
after, so when the task execution time is relatively long, it may cause delays task can not be executed on schedule. Consider the following code:
function sayHello() { console.log('hello') }
function test() {
setTimeout(sayHello, 0);
for (let i = 0; i < 5000; i++) {
console.log(i);
}
}
test()
Even if the delay time of the sayHello
0
, it needs to wait for test
to be executed before it can be executed, so the sayHello
is greater than the set time.
Macro task and micro task
New tasks added to the task queue need to wait for the other tasks in the queue to be executed before they can be executed, which is disadvantageous for sudden situation of 1619469360644a.
In order to solve the problem of timeliness, the tasks in the task queue are called macro tasks. During the
micro tasks can be generated
micro task queue in the task execution context.
That is, the right part of the flowchart:
In before the end of the macro task execution will traverse its
micro task queue, the
process macro task execution generated
micro-task batch execution.
MutationObserver
How do microtasks solve the problem of timeliness while taking into account performance?
Consider for monitoring DOM
changes in micro-task API
- MutationObserver
.
When multiple occurrences of the same macro task DOM
change, will produce more MutationObserver
micro tasks, the timing of its implementation before the end of the execution of the macro task, as compared to the new macro task into the queue waiting to be executed to ensure timeliness.
At the same time, because the DOM
in the microtask queue are executed in batches, the performance is better than when the callback is executed synchronously every time 06194693606531 changes.
Summarize
The implementation batch processing in the framework is very similar in
MutationObserver
advantage of the asynchronous execution of 16194693606579 macrotasks and
, package the updates and execute them.
It's just that different frameworks have different update granularity, such as Vue3
and Svelte
update granularity is very fine, so used to realize batch processing.
React
relatively coarse, but the internal implementation is more complicated, that is, there are scenes with macro tasks and scenes with micro tasks.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。