Event loop
1, ask questions
First of all, it’s 2021, so you’re familiar with tasks, MircoTask, and task Queue. But can you answer the following questions:
Task queue
Is it a queue,task
Will it be prioritized? What kind oftask
Higher priority?requestAnimateFrame
At what stage?requestIdleCallback
?Event loop
withBrowser rendering
What’s the relationship between?
Ok, if you can answer these questions, big guy please private message me your wechat, let’s come to in-depth exchange ♀😂; Don’t panic if you don’t know, this article is all about getting it right.
The following conclusions are all based on the HTML5 specification, English good partners can directly go to see
2, definitions,
2.1 Event Loop
In order to coordinate events, user interactions, scripting, rendering, networking, and so on, UA must use event loops. Each UA has an associated event loop that is unique to that UA.
UA refers to user Agnet, which includes the environment required for code to run — ECMAScript execution context, execution battle, execution thread, etc. However, execution thread does not belong to UA, so it is possible for one thread to cooperatively schedule multiple event loops.
This is complicated, but we can simply assume that each TAB page corresponds to an event loop.
2.2 Task Queues and tasks
An event loop has one or more task queues. A task queue is a Set of tasks.
Task queues are queues, not queues, because step one of the event loop processing model grabs the first runnable task from the chosen queue, instead of dequeuing the first task.
An event loop has one or more task queues, which are sets of tasks.
This solves our first problem: the task queue is not a queue, because the first step in the event loop execution process is to take the first available task from the selected task queue, rather than dequeuing the first task.
2.3 More than one task queue
For example, a user agent could have one task queue for mouse and key events to which the user interaction task source is associated, and another to which all other task sources are associated. Then, using the freedom granted in the initial step of the event loop processing model, it could give keyboard and mouse events preference over other tasks three-quarters of the time, keeping the interface responsive but not starving other task queues. Note that in this setup, the processing model still enforces that the user agent would never process events from any one task source out of order.
As mentioned above, a task loop can have multiple task queues, and each queue holds different types of tasks, such as:
- User interaction tasks such as mouse and keyboard
- Other tasks, such as postMessage, setTimeout, setIntervel, HTTP
Browsers assign three quarters of their priority to user interaction events in order of tasks to ensure a timely response without starving the rest of the tasks.
Vue’s nextTick implementation uses postMessage as a task with a low priority. The event loop selects the task queue for user interaction when the browser is scrolling. Render functions in postMessage were delayed and views were not updated. In later versions, You changed the nextTick implementation to the Mutation Observer and Promise.resolve schemes.
2.4 Event Loop Flow
-
Execute a macro task from the selected task queue
-
Check the microtask queue, execute the microtask, and empty the microtask queue. All the microtasks generated in the execution process are completed in this event loop
-
There is a concept called Rendering opportunities, which is used to determine whether a task needs to be updated after completion. In other words, the view is not updated once a task is completed, but more likely to be updated after multiple event loops.
-
Generally speaking, the view update interval is fixed, corresponding to the screen refresh frequency of 60fps, that is, each view update interval is 16.7ms, when the page performance can not maintain at this frequency, the browser will reduce the frequency to 30fps, to avoid losing frames.
-
When the browser context is not visible, the frequency can even drop to 4fps. The browser context here refers to pages that are not visible, such as iframe, the current TAB is not on the page, etc
-
The browser also skips the render when it determines that no changes will be made to the current render, and that the Map of AnimationFrame Callbacks are empty, meaning no requestAnimationFrame is called
-
Finally, there is the case when the browser decides that it is best to skip the update rendering for other reasons (mainly to incorporate the timer callback).
This step enables the user agent to prevent the steps below from running for other reasons, for example, to ensure certain tasks are executed immediately after each other, with only microtask checkpoints interleaved (and without, e.g., animation frame callbacks interleaved). Concretely, a user agent might wish to coalesce timer callbacks together, with no intermediate rendering updates.
-
When either of these situations occurs, skip all steps in 3.x.
3.1 If the page window size changes, directly execute the resize method
3.2 If the page is scrolled, perform the Scroll method directly
3.3 Performing a callback for requestAnimationFrame
3.4 Execute the callback of the Intersection Observer
3.5 Redraw the USER interface
-
-
Start the idle period algorithm, that is, the callback to requestIdleCallback.
For resize and Scroll, we don’t wait until the user interface is redrawn, so there is a lot of delay. As mentioned in the CSSOM VIEW, if it is resize, the browser will immediately trigger a resize event. Scroll is relatively complex. The browser will initialize a pending Scroll event targets. When the event loop triggers the scroll method, the element queue collected by targets will trigger scroll events in sequence, which is of course bubbly. If it’s an element’s Scroll event, we’ll cancel the document event.
Above is the basic flow of the event cycle, you can look at the diagram, the flow of the comparison slowly comb. Hopefully you’ll be able to answer the question at the beginning of this article perfectly.
There are a lot of details, but it’s too tedious to list them all, so if you want to know more, check out the HTML5 specification mentioned above
NextTick in Vue
Vue updates the DOM asynchronously
As described in the Vue documentation, when Vue modifies data, it does not immediately trigger an update of the Watcher, but instead pushes it into an asynchronous queue that sorts the watcher and executes them asynchronously, including DOM updates.
So let’s think, what stage should this so-called asynchrony be in? The answer is microtasks. Vue internally tries to use native Promise. Then, MutationObserver, and setImmediate for asynchronous queues, and if the execution environment does not support it, setTimeout(fn, 0) is used instead. This is the implementation of nextTick.
Take 🌰 for example
<div id="example">{{message}}</div>
<script>
var vm = new Vue({ el: '#example'.data: { message: '123' } })
vm.message = 'new message' // Change the data
vm.$el.textContent === 'new message' // false
Vue.nextTick(
function () {
vm.$el.textContent === 'new message' // true })</script>
Copy the code
-
The event loop is executing the macro task
-
vm.message = 'new message'
The triggersetter
That will berender Watcher
Put it on an asynchronous queue. Vue is calling internallynextTick
Put the asynchronous queue into the microtask queue -
Because the DOM has not been updated, so the first judgment
textContent
The value is123
, so it isfalse
-
The user has called
nextTick
.Push the callback to the microtask queueNote that the function is not being pushed into an asynchronous queuewatcher
And will be in the queuewatcher
It’s all done, and it’s done in one microtask. -
Task
After the execution is complete, the execution starts to empty the microtask queue. The first microtask is the one in the asynchronous queuewatcher
Update again -
watcher
All updates, DOM updates, and notice here, it’s a DOM update not a view update, because it’s up to the browser to update the view. If this is confusing, look at the flow of the event loop again. -
Execute the next microtask, which is true because the DOM has been updated.
Read on
- Vue’s nextTick implementation
- EventLoop and Browser rendering, frame animation, and idle callbacks that you didn’t know about
- NextTick: MutationObserver is just a cloud, microTask is the core!