Preface
We know that js is executed by a single thread, so how do asynchronous code js handle it? For example, how the following code outputs:
(1); setTimeout(function() { (2); }, 0); new Promise(function(resolve) { (3); resolve(()); }).then(function() { (4); }); (5); setTimeout(function() { new Promise(function(resolve) { (6); resolve(()); }).then(function() { (7); }); }, 0);
If it is not running, you can first guess the final output and then expand what we want to say.
1. Macro and micro-tasks
Based on our years of experience in writing ajax: js should be executed in the order of statements. When asynchronous occurs, the asynchronous request is initiated, and then the execution is carried out. After the asynchronous result is returned, it will be executed again. But how does he manage these tasks internally?
In js, tasks are divided into macro tasks (macrotask) and microtasks. These two tasks maintain a queue respectively, and both are executed using a first-in-first-out strategy! All tasks executed synchronously are executed on macro tasks.
The main macro tasks are: script (overall code), setTimeout, setInterval, I/O, UI interaction events, postMessage, MessageChannel, and setImmediate (environment).
The main micro-tasks are:, MutationObserver, (environment).
The specific operation steps are as follows:
- Take out a task from the head of the macro task to execute;
- If a microtask is encountered during execution, add it to the queue of the microtask;
- After the macro task is executed, whether there are tasks in the micro task queue? If they exist, they will go out to execute one by one until the execution is completed;
- GUI rendering;
- Return to step 1 until the macro task is completed;
These 4 steps constitute a circular detection mechanism for events, which is what we call eventloop.
Go back to the code we mentioned above:
(1); setTimeout(function() { (2); }, 0); new Promise(function(resolve) { (3); resolve(()); }).then(function() { (4); }); (5); setTimeout(function() { new Promise(function(resolve) { (6); resolve(()); }).then(function() { (7); }); }, 0);
The steps are as follows:
- Execute log(1), output 1;
- When encountering setTimeout, add the callback code log(2) to the macro task and wait for execution;
- Execute (3), add log(4) in then to the microtask;
- Execute log(5), output 5;
- When encountering setTimeout, add the callback code log(6, 7) to the macro task;
- After one task of the macro task is executed, check whether there is a task in the micro task queue, there is a micro task log(4) (added in step 3), and execute output 4;
- Take out the next macro task log(2) and execute it, and output 2;
- After one task of the macro task is executed, check whether the task exists in the micro task queue and does not exist;
- Take out the next macro task to execute, execute log(6), and add log(7) in then to the micro task;
- After the macro task is executed, there is a micro task log(7) (added in step 9), and the output 7 is executed;
Therefore, the final output order is: 1, 3, 5, 4, 2, 6, 7;
We are implementing a slightly time-consuming operation, and this step will look more obvious:
(1); var start = (); setTimeout(function() { (2); }, 0); setTimeout(function() { (4, () - start); }, 400); ().then(function() { var sum = function(a, b) { return Number(a) + Number(b); } var res = []; for(var i=0; i<5000000; i++) { var a = (()*100); var b = (()*200); (sum(a, b)); } res = (); (3); })
In, it forms an array of 5 million random numbers, and then sorts the array. Running this code will reveal that 1 will be output immediately, 3 will be output after a while, and then 2 will be output. No matter how long you wait, 3 will be output after 3. This confirms the third step in eventloop. You must wait until all the micro tasks are executed before the next macro task begins.
At the same time, the output of this code is interesting:
setTimeout(function() { (4, () - start); // 4, 1380 The output time difference is different for different computer status}, 400);
Originally, the output after 400ms was set, but because the previous tasks were time-consuming, the subsequent tasks could only be delayed to the back row. It can also be explained that the delay of operations such as setTimeout and setInterval is inaccurate. These two methods can only focus on the macro tasks after about 400ms, but the specific execution time still depends on whether the thread is idle. If there are time-consuming operations in the previous task, or if there are infinite micro-tasks added, the execution of the next task will be blocked.
2. async-await
From the above code, you can also see that the code in it belongs to a microservice, so how to execute the code of async-await? For example, the following code:
function A() { return (()); } async function B() { (()); let now = await A(); (now); } (1); B(); (2);
In fact, async-await is just a syntactic sugar for Promise+generator. We rewritten the above code to this, which makes it clearer:
function B() { (()); A().then(function(now) { (now); }) } (1); B(); (2);
In this way, we can understand the order of outputs: 1, 0.4793526730678652 (random number), 2, 1557830834679 (timestamp);
3. requestAnimationFrame
requestAnimationFrame also belongs to a method of execution asynchronous execution, but I do this method belongs to neither a macro task nor a micro task. according toMDNDefinitions in:
() Tells the browser - you want to execute an animation and asks the browser to call the specified callback function before the next repaint to update the animation. This method requires passing a callback function as a parameter, which will be executed before the next repaint of the browser
The requestAnimationFrame is executed before GUI rendering, but after microservices, the requestAnimationFrame may not necessarily be executed in the current frame. The browser decides which frame to execute according to the current policy.
4. Summary
We need to remember the two most important points: js is a loop mechanism for single thread and eventloop.
OK, the above is the entire content of this article. I hope that the content of this article has certain reference value for your study or work. Thank you for your support.