1. Understand JS asynchronous programming:
Because js language is initially positioned as a browser scripting language, in order to do interaction for the web page, web page interaction, we know that all DOM operations, if there are two threads, one thread to update the DOM, the other thread to delete the DOM, at this time the browser does not know which thread to process the results. So JS chooses the single-threaded working model. But the single-threaded working model, if all code execution is synchronous. Asynchronous programming occurs when a piece of code becomes too time-consuming, subsequent code fails to execute, the rendering process stops, and the browser enters a state of suspended animation.
2. EventLoop
For a simple scenario, if we give a thread four tasks, the tasks will be written to the main thread in sequence and executed in sequence, and the thread will exit automatically after execution. However, not all tasks are uniformly scheduled before execution. In most cases (user interaction events, resource requests, scheduled tasks, etc.), new tasks are created while the thread is running. For example, in the middle of thread execution, a new task is received to calculate “10+2”, then the above method does not handle the situation.
So, in order to receive and execute new tasks in a thread, you need to use an event loop (you can use a for loop to listen for new tasks).
In order to handle the new tasks that are created while the thread is running, two changes need to be made.
The first point introduces the loop mechanism, adding a for loop statement at the end of the thread statement, so that the thread keeps executing the second point introduces the event. During the execution of the thread, it waits for the number input by the user. During the waiting process, the thread is in a suspended state
So in the process of a thread running, the solution to the new task to deal with that thread is the solution of the event loop, which is how the event loop comes out
3. Message queues
Consider: the above event loop solves the problem of how to handle new tasks created within a thread, but what if the main thread handles tasks sent from other threads? How to deal with. You can’t just do it with an event loop.
For example, in the render process, there are render main thread and IO thread. The resource loading of IO thread, mouse click and other events need to be handled by render main thread. The renderer receives these tasks and needs to process them before the main thread can parse the DOM.
So how do you design a thread model that can receive messages from other threads?
A common pattern is to use message queues: message queues are data structures that hold tasks to be executed. There are fifO features added from the tail and removed from the head at the tail.
With message queues, tasks (messages) generated by events in IO threads are added to the tail of the queue first, and the render main thread executes tasks that are read in a loop from the header of the message queue.
The renderer has an IO thread that receives incoming messages from other processes and then assembles them into tasks that are sent to the main render thread. You just need to add tasks to the message queue.
Microtasks and macro tasks
All tasks executed by the page thread come from the message queue, which is a “first in, first out” property, meaning that tasks placed in the queue wait for the previous tasks to complete before they are executed. Between fifO attributes, there are two problems to solve. The first problem is that a typical scenario is to monitor DOM node changes (dynamic insertion, modification, deletion, etc.) followed by (Promise), and then process the corresponding business logic based on those changes. A generic design is a set of listening interfaces that the rendering engine calls synchronously when changes occur, which is typical of the observer pattern. This pattern is problematic because the DOM changes very frequently, and if the corresponding javascript interface is used directly every time a change occurs, the execution time of the current task will be lengthened and the execution efficiency will be reduced
If these DOM changes are added to the end of the message queue as asynchronous message events, then the real-time monitoring will be affected, because many tasks may be queued before adding to the message queue.
Therefore, if the DOM changes, the synchronous notification will affect the efficiency of the current task. If the asynchronous mode is adopted, the real-time monitoring will be affected.
So what’s the trade-off between efficiency and real-time? Microtasks came into being in response to this situation.
We will be the inside of the message queue task usually referred to as macro task, each contains a small task in the macro task queue, in the process of performing macro task queue, if there is the DOM have change, so this change will be added to the task list, so as not to affect the macro task to continue, so that solve the problem of the execution efficiency
After the main functions of the macro task are directly completed, the rendering engine is not in a hurry to execute the next macro task at this time to execute the micro task of the macro task, because the DOM change events are stored in the micro task queue, which solves the real-time problem.
Synchronous notification has low execution efficiency for some DOM changes with frequent changes. If asynchronous execution is used, real-time performance is insufficient. Therefore, microtask is used to balance the optimal execution efficiency and real-time performance. It is more effective than asynchronous scheme and more efficient than synchronous scheme. So there is a micro task in the macro task, the current synchronization of the code and the macro task to execute the micro task