EventLoop, message queue, macro task, micro task

1. First understand what is synchronous and what is asynchronous:

Let’s take a simple example: if you come home from work and need to do two things, boil a pot of water and go to the bathroom to take a shower. If you do these two things synchronously, first boil the water and wait for the water to boil and then take a shower. If you do these two things asynchronously, first boil the water and then take a shower while the water is boiling.

This example may not be very relevant, as callback functions are involved in asynchronous JS operations, but it will help you understand the concept of asynchronous programming.

2. Why JS is single threaded:

JS is supposed to be responsible for the interaction between the browser and the user. Because you need to manipulate the DOM, it must be single-threaded. Imagine if there are multiple threads working on the same DOM element at the same time, the browser will be confused. However, the queuing mechanism of sequential execution has many disadvantages, so JS provides an asynchronous programming scheme.

3. Asynchronous programming scheme and callback function:

There are many ways to implement asynchronous programming: callbacks, Promise objects, event listeners, publish/subscribe, etc. At the heart of it all is the callback function. Callbacks are the foundation of all asynchronous programming schemes, and the example of boiling water and taking a shower.

If we were in the boiling water after put the boiled water into the thermos flask, you need to tell your friends about this, that the asynchronous process becomes boiling water first, then tell your friends and other water burn well to pour into the glass and then you take a shower, in this process, pour the water into the cup is a callback function, which is upon the completion of the tasks you need to do, You are the caller of the asynchronous operation, and your friend is the performer of the asynchronous operation, which is defined by the caller and given to the performer to execute is called the callback function.

4. EventLoop:

In real development, there will be a lot of synchronous and asynchronous tasks, so what is the order of execution? This involves event polling, which is basically a specification that specifies the order in which tasks are executed in the browser. What is the order?

5. Stacks and queues:

The difference is that the queue is fifo, while the stack is lifo. If there are five tasks in the queue, the execution order is 1,2,3,4,5. If there are five tasks in the queue, the execution order is 1,2,3,4,5.

In the browser, there is a Call Stack and a Queue. As the code executes from top to bottom, tasks are pushed into the Call Stack and ejected when they are finished

6. Message queue:

A message queue is a container used to store callback functions, so it is also called a callback queue. When the call stack is empty, the browser polls the message queue to execute the tasks in the message queue in order.

7. Macro versus micro tasks

Common macro tasks include setTimeout, setInterval, UI interaction events, etc. Common micro tasks include Promise.then, Object.observe, etc. These are just things to remember.

If you have to explore the difference between macro and micro tasks, here are some ideas:

  1. Macro tasks are initiated by a host, such as a browser or Node (Node is not discussed in this article, for example); Microtasks are initiated by the JS engine
  2. Macro tasks are executed in another thread, microtasks are not (you may wonder: isn’t JS single threaded? JS is single-threaded, but browsers are not single-threaded. For example, the setTimeout countdown is handled separately by other threads in the browser.)
  3. The code executed by each execution stack is a macro task, while a microtask is a task executed immediately after the execution of the current task

The directions of these ideas are different. If you can’t understand them temporarily, you can remember them first and verify them slowly in the application.

8. Sequence of EventLoop execution

Finally, here we go!

An EventLoop listens to the Call Stack and Queue. Once the Call Stack is empty, the EventLoop pulls the first callback function from the Call Stack and pushes it into the Call Stack.

EventLoop (easy to Understand version) Code executed from top to bottom, if there are any tasks on the micro task queue, acer tasks into the task queue, after completion of all synchronous code execution, go to the micro task queue in all the tasks are performed, and then to acer in the task queue in order to perform the task, each performed a macro tasks, will go to the micro task queue to see if any new tasks, If so, the microtask is executed, and if not, the next macro task is executed until all tasks are completed.

The EventLoop I mentioned above is perfectly adequate for doing interview questions. But I’ve done a lot of research, and some people think that there is no microtask queue at all, that a microtask is a task that is executed immediately after the current macro task is executed, and you can think of all the code in the call stack as a big macro task, so the microtask is executed immediately after the big macro task is executed.

Either way, one thing is clear: microtasks don’t have to queue up at the end of the queue to be executed again, so you can think of microtasks as “interludes” between the end of the current macro task and the start of the next macro task.

Exercise: Make the following asynchronous code a Promise improvement

setTimeout(function () { var a = 'hello'; setTimeout(function () { var b = 'world'; setTimeout(function () { var c = 'I am programmer'; console.log(a + b + c); }, 10)}, 10)}, 10)Copy the code

To summarize the above code:

  1. becauseconsole.log(a + b + c)A and B are referenced, so the closure holds these two variables, and the code ends up printing helloworldI am Programmer
  2. Each timer has a 10-millisecond delay

With no timer and just passing variables, it would be easy to write:

var p = new Promise(resolve => {
  var a = 'hello';
  resolve(a);
})
p1.then(a => {
  var b = 'world';
  return a + b;
}).then (value => {
  var c = 'I am programmer';
  console.log(value + c);
})
Copy the code

But a, B, and C are all assigned in the timer, so if we just put the timer in the.then, the next.THEN will only get the return value of the timer, which is not what we want, so we have to return a Promise object in the.THEN. Let’s change the code above:

var p = new Promise((resolve) => { setTimeout(function () { var a = 'hello'; resolve(a); }, 10) }) p.then(a => { return new Promise(resolve => { setTimeout(function () { var b = 'world'; resolve(a + b); }, 10) }) }).then(a => { return new Promise(resolve => { setTimeout(function () { var b = 'I am programmer'; console.log(a + b); }, 10)})})Copy the code

So you get the same effect.

Hope to read the article to help, if there are ambiguities in the place can discuss modification ~