I found a lot of articles related to event cycle and task queue on the Internet, some of which are not very clear, and I still feel dizzy after reading them, so I write this blog to sort out the overall idea. If you have any different understanding or confusion, please leave a comment. This is my Github, welcome to visit.
Event loop and task queue are two important concepts in JS. These two concepts have different implementations in ES5 and ES6 standards. Especially in the ES6 standard, a clear distinction between macro and micro task queues explains some of Promise’s seemingly strange behavior.
Event loop
What is the event loop? Why is there an event loop? We all know that JS is single-threaded, but time-consuming operations like Ajax or DOM events need to be handled concurrently, otherwise a single thread will wait too long to do anything. Single-threaded loops are a form of concurrency, with only one event loop per thread. While task queues are used to complete operations in conjunction with the event loop, a thread can have multiple task queues.
Task queue
What is a task queue? So name think meaning, line up the task of the queue. A task is a notification returned by WebAPIs that tells the main JS thread that the asynchronous task has completed when it reads the task queue, and that the next step is to execute the callback function of the task. The main thread has multiple task queues, and different task queues are used to arrange tasks from different task sources. What is the source of the task? Such as setTimeout/Promise/DOM events are task sources. Tasks from similar task sources are said to be homologous. For example, setTimeout and setInterval are homologous. In ES6 standard, task queue is divided into macro task queue and micro task queue, which will be discussed in detail later.
Here is a general description of the event loop in ES5, as shown below (according to ruan yifeng’s tutorial) :
There are three big blocks in the picture:
- Function call stack: execution stack.
- WebAPIs: Browser interfaces. For example, a
Ajax
Operation, the main thread will send and receiveAjax
Handed to the browserAPI
And then it goes on to do something else, and the browser is picking upAjax
After the data is returned, aAjax
Completed events are placed behind the corresponding task queue. - Task queues: There are multiple task queues in the main thread. Same-origin tasks are placed in their own task queues.
A more specific chestnut. For example, a page opens with a
- The main thread is encountering
Ajax
orsetTimeout
This asynchronous operation will be handed to the browserWebAPIs
, and continue to execute until the stack is empty. - The browser will return the completed tasks at an unspecified time to the corresponding task queue.
- When the stack is empty, the main thread fetches tasks from the task queue, which tell you which callback functions to execute next. Task queues are prioritized, and the order of access is determined by priority. Priorities vary in different environments, so you can’t give a fixed priority.
- Each time a queue is accessed, the stack executes all the code in the task queue and fetches the code in the next task queue. If an asynchronous task currently belongs to the task queue is encountered during execution. The return of this task is not directly after the current task queue. Because these are two separate cycles of events, they will be separated.
This loop continues until all three blocks are empty, which is called an event loop.
Microtask queue
There are two types of task queues in ES6 standard. One is the microtask queue mentioned above, such as setTimeout, network request Ajax, user I\O, etc., and the other is macroTask Queue. Promises are part of the microtask queue. What happens to the event loop when you add microtask queues? In the process of execution stack, the tasks belonging to the micro task queue will be allocated to the corresponding micro task queue. After the call stack is empty, the main thread reads all the micro task queues first, then a macro task queue, and then all the micro task queues. As shown in figure:
Ok, a lot of conceptual stuff, not as clear as a piece of code:
setTimeout(function(){console.log(4)},0); new Promise(function(resolve){ console.log(1) for( var i=0 ; i<10000 ; i++ ){ i==9999 && resolve() } console.log(2)}).then(function(){ console.log(5)}); console.log(3);
- Script starts execution, first encountered
setTimeout
Hand it to the browser for timingsetTimeout
After limiting the minimum timing, push the task insetTimeout
The queue. - encounter
Promise
Constructor, constructor arguments execute, output1
, the callresolve
changePromise
Object state, and then output2
. Promise
The objectthen
Method to push the task inPromise
Task queues.- perform
console.log(3)
And the output3
. - Call stack is empty, read the task queue, according to
Read all microtask queues -> perform ->
Read a macro task queue -> perform ->
Read all microtask queues -> perform ->
Read another macro task queue… The order. - Reads all tasks in the microtask queue and executes the callbacks specified by those tasks. perform
then
The specified callback function outputs5
Microtask queues also have priorities. - Finally read
setTimeout
Execute the callback function to output4
.
So the final output order is 1,2,3,5,4, not 1,2,3,4,5. If the execution mechanism of the micro task queue is not clear, it is easy to lump two asynchronous tasks together and judge the execution order incorrectly.
Here is the event loop and task queue said more clear, refer to a lot of bosses blogs and discussion: www.ruanyifeng.com/blog/2014/1… www.zhihu.com/question/36… www.jianshu.com/p/12b9f73c5… www.cnblogs.com/hity-tt/p/6…
If you have different understanding, please leave a comment below the blog, this is my Github, welcome to visit, your star is my motivation.
- Kongcheng.LC
- Links to this article: Kongchenglc. Making. IO/blog/event loop 20…
- Copyright Notice: All articles on this blog are licensed under a CC BY-NC-SA 3.0 license unless otherwise stated. Reprint please indicate the source!