preface

This article was originally posted by the Nuggets @Blackgold team and is now posted to my account

In our last post @tdGarden said: It’s spring and everything is alive again and everyone is too busy dating to blog. Then he sent me a picture in the group:


All right, let’s get down to business and talk about the Event Loop. This article is a summary and sorting of the learning of Event Loop in these days. I refer to many articles of big wigs. If there are any mistakes, please correct them.

Let’s start with single threads

Js is known to be a single-threaded language. Why single thread? Let’s say we have two threads. One thread wants to add content to a DOM node, and the other thread wants to delete it. Of course, there is a multi-threaded solution to multi-threading, locking ah, but this will introduce locking, state synchronization and other issues.

Js is a browser scripting language. Its main purpose is to interact with users and operate DOM. Multi-threading will bring very complex synchronization problems.

Ok, single thread then. However, single threading brings with it the problem of single threading. With only one thread, tasks have to be queued, and if the previous task takes a long time to execute (ajax requests for background data), subsequent tasks have to wait.

The Event Loop is here to back up the single-threaded mess.

Event Loop

Before moving on, you should know the basic concepts of stack, queue, synchronous task, asynchronous task, and execution stack.

There is a very detailed article on execution stacks recommended: JavaScript deep execution Context stacks

See the picture below:

  1. Js in the execution of the code, the code first into the execution stack, the code may contain some synchronous tasks and asynchronous tasks.

  2. The synchronization task is executed immediately, and then the stack is removed, over.

  3. Asynchronous tasks are common Ajax requests, setTimeout, etc. When code calls these apis, the WebAPIs handle these issues and the execution stack continues.

  4. When the asynchronous task has a result to run (when the Ajax request result returns), the WebAPIs put the corresponding callback function on the task queue.

  5. When the stack is empty, the first function in the task queue is read and pushed onto the stack.

Step 5 is repeated repeatedly. If the execution stack is empty, the system pushes the first function in the task queue to continue execution. This process is repeated over and over again. This is called an Event Loop.

Let’s look at a simple demo.

console.log(1);

setTimeout(() => {
    console.log(2);
}, 2000);

console.log(3);
Copy the code
  • console.log(1)Synchronization task, output 1
  • setTimeoutAsynchronous tasks, handed over to Webapis, and after 2 seconds,console.log(2)Entering a Task queue
  • console.log(3)To synchronize tasks, output 3
  • When the stack is empty, the system reads the events in the task queue
  • performconsole,log(2)And the output 2

Macro tasks & micro tasks

That’s not the end of it, of course. I’m sure you’ve seen process.nextTick and promise, where the order of execution can get a little complicated. Scroll down.

Microtasks, macro tasks, and event-loops use very common examples to explain the difference between macro tasks and microtasks, so I won’t bother here. It’s ok if you don’t want to know, because there are only a few common macro tasks and micro tasks. Just remember them.

  • Common macro tasks:Script (whole code),setTimeout,setInterval,I/O,setImmedidate
  • Common microtasks:process.nextTick,MutationObserver,Promise.then catch finally

Process. nextTick and setImmidate are Node only.

Also, Process. nextTick has a queue-jumping operation, meaning that when it enters the microtask queue, it will be queued in front of all other microtasks except process.nextTick.

So, the task queue we mentioned above consists of a macro task queue and a micro task queue. Each time the execution stack is empty, the system will first process the microtask queue, process all the tasks in the microtask queue, and then process the macro task.

Do two problem

After all that, let’s try two questions.

new Promise(resolve => {
    resolve(1);
    Promise.resolve().then(() => console.log(2));
    console.log(4);
}).then(t => console.log(t));
console.log(3);
Copy the code

Hahahhhhh I moved out of the ruan teacher’s question.

  • First of all,new PromiseTo perform,resolve(1)Indicates that the state of the created Promise object has changed to Resolved
  • Promise.resolve()A promise object is created, and the anonymous callback function inside then enters the microtask queue, which is called[() => console.log(2)]
  • The output of 4
  • new PromiseThe anonymous callback in the then function of the[() => console.log(2), t => console.log(t)]
  • The output of 3

So, the final output order is 4, 3, 2, 1.

If you don’t understand, I think you should go over the promise.

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2');
}
console.log('script start');
setTimeout(function() {
  console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
  console.log('promise1');
  resolve();
}).then(function() {
  console.log('promise2');
});
process.nextTick(() => {
  console.log('nextTick');
})
console.log('script end');
Copy the code

This is a bad job interview question. I can’t believe you haven’t. Without further ado, let’s analyze EMMMMM. I recommend that you do it yourself first and then move on.

Don’t be nervous to see async/await, it’s just syntactic sugar. Async means that an asynchronous operation is performed in a function, and the code before an await operation should be executed, the expression to the right of an await operation should be executed, and the code following the await operation is blocked. When a non-Promise object is returned, the following code is executed; When the Promise object is returned, wait until the Promise object is resolved.

The code goes into promise.then.

  • The outputscript start
  • WebAPIs will be available in 0s (oh, like the shortest is 4ms)setTimeoutThe anonymous callback function inside is thrown into the macro task queue, denoted as['setTimeout'](Remember that the callback is thrown into the task queue, function!)
  • The outputasync1 start
  • The outputasync2
  • To the outputasync1 endThe code is thrown into the microtask queue, which is['async1 end']
  • The outputpromise1
  • promiseObject state changes toresolved
  • promise.thenWhere, the anonymous function enters the microtask queue, and the microtask queue is['async1 end', 'promise2']
  • nextTickCut to the head of the microtask queue,['nextTick', 'async1 end', 'promise2']
  • The outputscript end
  • Execution stack is empty
  • The outputnextTick
  • The outputasync1 end
  • The outputpromise2
  • The microtask queue is empty
  • The outputsetTimeout

conclusion

If after reading this article you still do not understand, then I suggest you can read several articles, a baked cake is not enough to eat, ten is about the same.

This article doesn’t go into details about promises, async/await, and the difference between Node and browser Event loops, but it will help you get a better handle on Event loops.

Eventloop is not terrible. What is terrible is meeting a promise.

Refer to the article

  • Understand Event Loop for the last time
  • Figure out the JavaScript engine Event Loop
  • This time, thoroughly understand the JavaScript execution mechanism
  • More on the Event Loop

The last

Above, if there are mistakes, please correct!

Amway my official account. (Non-technical number) Here is the text of Tangtang, a rational analysis of social phenomena, but also the warmth of daily life. I’m the code life host. Welcome.