Now that we're talking about JavaScript's event loop mechanism, to understand the event loop, first know what the event loop is.
Let's look at the sequence of JavaScript execution from an example.
<script>SetTimeout (function() {Console.log (' The timer has started. '); },0)NewPromise (function(Resolve) {Console.log (' Execute for Loop now '); for(Let i = 0; i < 10000; i++) {i= ~ &&Resolve (); }}). Then (function() {Console.log (' Execute then function '); }) Console.log (' End of code execution '); //The result of the execution is: //execute the For loop now. //end of code execution //executes the then function. //the timer started.</script>
How, is not and own in the heart to run the result to be 18,000 in the difference. If so, be patient with the rest of the content and let you thoroughly understand the JavaScript event loop mechanism.
Single thread of JavaScript
To understand the event loop we have to start with how JavaScript works.
One of the features of the JavaScript language is single-threaded, but why isn't JavaScript made multithreaded?
The single thread of JavaScript is related to its purpose. As a browser scripting language, JavaScript's primary purpose is to interact with the user and manipulate the DOM. This determines that it can only be single-threaded, otherwise it can lead to complex synchronization problems. For example, assuming that JavaScript has two threads at the same time, one thread adds content to one of the DOM nodes, and the other thread deletes the node, which thread should the browser take precedence over?
Task Queue
We say that a single thread means that all tasks must be queued. Just like a bank has only one window, the last task can be executed after the execution of the previous one is completed. If the newly executed task takes a long time, the latter task will have to wait.
Then there is a problem, in the browser operation, we often through the Ajax to send requests to the background, but JS must wait until the browser receives the response content will not continue to execute, if this period is 10s, then the page must be parked here 10s. This will not only affect the user experience, but also reduce CPU utilization , which is obviously not what we want.
So the clever programmer's little brother divides the task into two categories.
- Synchronization Tasks
- Asynchronous task
A synchronization task is a task that is queued on the main thread, and only the previous task is executed to perform the latter task;
An asynchronous task refers to a task that goes into the task queue without entering the main thread, and only the task queue notifies the main thread that an asynchronous task can execute and the task goes into the main thread, and usually the task that owns the callback callback function is the asynchronous task.
The execution of synchronous and asynchronous tasks can be roughly simplified as shown in the following map.
- The synchronous and asynchronous tasks enter different execution "places", enter the main thread synchronously, enter the event table asynchronously and register the function.
- When the specified event is complete, the event table will move the function into the event Queue.
- When the task in the main thread is completed empty, it will go to the event queue to read the corresponding function and go into the main thread execution.
- This process repeats itself, which is often called the event loop.
To facilitate understanding of the event loop, let's look at a piece of code.
<script> console.log (1); SetTimeout (
Console.log (' timer executed. ')
},1000
Console.log (2); </script>
- The JS code executes from the top down,
- Encountered Console.log (1), executed and printed out:
- Encounters an asynchronous task Settimeout,task enters event table and registers, timing begins.
- Encountered Console.log (2), executed and printed out.
- The main thread executes and starts querying the task queue for any callback functions waiting to be executed.
- After one second, the timeout timer event completes and the task enters the event Queue.
- The main thread discovers that the task queue has a function task waiting to execute, and the task redeployment into the main thread execution.
We can't help but ask, how do you know the main thread execution stack is empty ah? JS engine exists monitoring process , will continuously check whether the main thread execution stack is empty, once empty, will go to the event queue to check if there is a function waiting to be called.
Macrotask and Microtask
In addition to the generalized synchronization tasks and the Division of asynchronous tasks, asynchronous tasks can be subdivided into macro tasks (Macrotask) and micro Tasks (Microtask). Different types of asynchronous tasks enter different event queues.
Macro tasks: Multiple event loops are required to complete, and each event in the event queue is a macro task . Each event loop will be transferred into a macro task, the browser in order to enable the JS Internal macro task and Dom task execution, after a macro task execution ends, before the next macro execution begins, the page is re-rendered (task-> rendering->task-> )。 For example, a mouse click Triggers an event callback, a macro task needs to be performed, and then the HTML is parsed. The role of settimeout is to wait for a given time to generate a new macro task for its callback.
Micro task: Micro-task is executed once. A micro task is typically a task that needs to be performed immediately after the execution of the current task, such as reacting to some actions or performing tasks asynchronously without assigning a new task, which can improve performance. as long as no other JS code in the execution stack is executing, and the macro task currently being transferred is executed, the Micro task queue executes immediately . If the micro task queue joins a new micro task during the micro-task execution, the new micro-task is added to the tail of the queue and then executed.
Simply understood, the macro task is executed in the next round of events, and the micro-task executes after all the tasks in this round of the event loop are completed .
- Macro tasks mainly include: SetTimeout, SetInterval, setimmediate, I/O, various events (such as mouse click events) callback function
- Priority: Main code block > Setimmediate > Messagechannel > Settimeout/setinterval
- Micro-tasks mainly include: Process.nexttick, Promise, Mutationobserver
- Priority: Process.nexttick > Promise > Mutationobserver
According to WHATWG specification Introduction:
- An event loop will have one or more task queues (tasks queue)
- Each of the event loops has a microtask queue
- Task Queue = = Macrotask Queue! = Microtask Queue
- A task can be placed into the macrotask queue or into a microtask queue
- The call stack empties (global only) and then executes all the microtask. After all executable microtask have been executed. The loop starts again from Macrotask, finds one of the macro tasks executed, if the macro task may contain a macro task or micro-task, will add the macro task to the event queue, and then perform all the Microtask, so the loop continues.
The macro task, micro task execution flowchart is shown below.
At this point, let's take a look at the code at the beginning of the article.
<script>SetTimeout (function() {Console.log (' The timer has started. '); },0) NewPromise (function(Resolve) {Console.log (' Execute for Loop now '); for(Let i = 0; i < 10000; i++) {i= ~ &&Resolve (); }}). Then (function() {Console.log (' Execute then function '); }) Console.log (' End of code execution '); //The result of the execution is: //execute the For loop now. //end of code execution //executes the then function. //the timer started.</script>
The steps to perform are as follows.
- When the page first loads, the code snippet within the,<script> tag enters the main thread as a macro task, and then executes down.
- You encounter an event queue that settimeout the callback function and then presses into the macro task.
- When the new promise is encountered, the output ' executes for loop ' immediately. Press the then function into the Micro task queue.
- Encounter Console.log (' End of Code execution '), execute code. The output "code execution is over".
- After the main thread executes, check that there are no pending tasks in the micro-task queue, and find the then function in the Micro task queue, take it out to the main thread execution, and output "execute then function".
- Start the next round of event loops, remove the callback function for the SetTimeout event from the Red task queue, and execute. The output "timer has started".
- End.
Summarize
JavaScript is a single-threaded language, and event loops are a method of JS asynchronous programming. It is also the execution mechanism of JS. When the Web page in the browser is just loaded, the code in the,<script> will be pressed into the stack as the first macro task, and after the synchronization code executes, if there is a micro task to perform the micro task, no micro task will perform the next macro task. This cycle is repeated until all tasks are completed.
Reference articles
A detailed explanation of JavaScript running mechanism: Another talk about event Loop
Event queues within the browser
This time, get a thorough understanding of the JavaScript execution mechanism
JavaScript execution mechanism-event Loop