1. Start with setTimeout, as we all know

SetTimeout is used a lot in code, both front-end and server-side, to delay execution.

SetTimeout (() => {console.log(' delayed execution '); }, 1000);Copy the code

There seems to be nothing to talk about.

2. Tell us more about setTimeout, which we may not know

We may have a problem where a piece of code needs to be executed in a piece of logic, but nothing works. Finally, with a setTimeout and a try, the program runs correctly.

Let me write a specific one that we use in real projects:

The requirement is that a popup box pops up when you click a button, and then click any area outside the popup box, and the popup box disappears. But if you click anywhere and on any element in the popbox, the popbox will not disappear.

<body> <button type="button" class="clickBtn"> </button> <div id="mask"> <p class="title"> </p> <p> <span < span> <a href="javascript:;" > Jump </a> </p> </div> <script type="text/javascript"> document.querySelector('.clickBtn').adDeventListener ('click', () => { document.querySelector('#mask').style.display = 'block'; setTimeout(() => { window.addEventListener('click', hides, false); }, 0); }); function hides(e) { document.querySelector('#mask').style.display = 'none'; window.removeEventListener('click', hides, false); } document.querySelector('#mask').addEventListener('click', e => { e.stopPropagation(); }); </script> </body>Copy the code

Through the above writing, setTimeout is very convenient to realize the page function, and there is no need to go through all kinds of E.target judgment to realize.

SetTimeout (()=>{},0) In order to understand why a setTimeout works, and why pop-ups don’t show and hide correctly without it, you need to know an important concept: event-loop. The event loop.

event-loop

The event loop mechanism is actually analyzed quite a bit on the website, and it is well analyzed. Finally, I will attach a link to a good article for your reference.

I want to mention event-loop at a macro level

Event-loop is implemented differently in Nodes than in browsers. Node is implemented through the Libuv library, while browsers are implemented by different vendors. I’m not talking about Node here, but how browser vendors handle time loops.

There are important meanings that need to be cleared. An event loop means that events are executed in a loop. An event loop has one or more task queues. The tasks in each task queue are executed strictly in first-in, first-out order, but the execution order of tasks in different task queues is uncertain.

So which behaviors belong to tasks or microtasks? The standard is not stated, but various technical articles are summarized as follows (excluding Node) :

  • macrotasksScript, setTimeout, setInterval,
  • microtasks Promise

“The following model illustration comes from resources.”

Take a look at the process model of the event loop described in the standard:

1. Select the task queue to be executed and the task that enters the task queue first. If no task is available, the system switches to the microTask execution step.

2. Set the current running task of the event loop to the selected task.

3. Run the task.

4. Set the current running task of the event loop to NULL.

Removes the finished task from the task queue.

5. Microtasks step: Perform a Microtask checkpoint.

6. Update the interface rendering.

7. Go back to step 1.

The user agent performs the following steps when entering the MicroTask checkpoint:

Set the flag to true for entering the MicroTask checkpoint.

When the microtask queue of the event loop is not empty: select a microtask that enters the microtask queue first. Set the current running task of the event loop to the selected MicroTask; Run microtask; Set the current running task of the event loop to NULL; Remove the finished Microtask from the MicroTask queue.

Notify each Environment Settings Object of the corresponding event loop which promises are Rejected.

Clear transactions for indexedDB.

Set the flag for entering the MicroTask checkpoint to false.

So it’s time to take an example, the above knowledge is a little difficult to understand.

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');
Copy the code

Of course, if the browser you’re testing supports promises that don’t support the Promise/A+ standard, or if you use another Promise polyfill, the results may differ.

The results are as follows:

script start
script end
promise1
promise2
setTimeout
Copy the code

The specific steps are explained in detail in the attached link, so I won’t be verbose. Knowledge would like to emphasize the whole cycle of events:

In the first event loop, there is only one task, which is js load -> put setTimeout and promise into macroTasks and MicroTask queues respectively -> after js executes, Enter the next event loop -> Execute all tasks in the MicroTask task queue -> execute one task in macroTasks. After the current macrotask is executed -> Execute all microtasks again if the microtask queue is not empty at this time. If the microtask is empty, Execute the next macroTask -> Finish and continue the next event loop

Now go back to the popbox example I wrote earlier, and you can see why setTimeout should be executed after 0 seconds. The root cause is that setTimeout is a task that needs to be executed at the next time period.

setTimeout(() = > {
   console.log(1); 
},0)

setTimeout(() = > {
    console.log(2);
    Promise.resolve().then(() = > console.log('promise1'));
    Promise.resolve().then(() = > console.log('promise2'));
}, 0)
setTimeout(() = > {
    console.log(3);
}, 0)


Copy the code

The execution result is:

1
2
promise1
promise2
3

Copy the code

3. Time loop execution sequence in node

The event loop in Node, in general, was implemented differently from the browser before Node9. Macro tasks are executed differently for parts of the same API. For example, the same example above is executed in Node 8.x in this order:

1
2
3
promise1
promise2
Copy the code

In higher versions of Node, it is aligned with browser features. So when it comes time to go live, be aware of the node version and watch out for these potholes if it builds on the wire.

4. About promises in the event loop

SetTimeout is simple, straightforward, and easy to understand and use. When it comes to promises, however, it can be a bit difficult, and promises can be used if they only involve simple scenarios, such as New Promise((resolve, reject)). Then () However, when it comes to complex scenarios, there are pitfalls. If you don’t really understand the principle, it’s easy to fall into the pit.

For a more detailed analysis of promises, see my article: Digging from event loops to Promises.