“Live up to the time, the creation of non-stop, this article is participating in 2021 year-end summary essay competition”

Threads and processes

We often say that JS is single-threaded, meaning that there is only one main thread in a process.

So what exactly is a thread? What is a process?

Officially, processes are the smallest unit of CPU allocation. Threads are the smallest unit of CPU scheduling.

  • Processes are like factories that have their own factory resources.

  • Threads are like workers, multiple workers working together in a factory. A process consists of one or more threads, which are different execution paths of code in a process.

  • Workers share space in the factory. The memory space of the process is shared, and each thread can use the shared memory.

  • Multiple factories exist independently of each other.

Multiprocess versus multithreading

Multiple processes

If two or more processes are allowed to run on the same computer system at the same time. The benefits of multiple processes are obvious. For example, a colleague listening to lyrics can open the editor and type code. The editor and the listening software process do not interfere with each other at all.

multithreading

There are multiple execution flows in a program, that is, multiple different threads can run simultaneously in a program to perform different tasks. Allows a single program to create multiple threads of parallel execution to complete their respective tasks. In Chrome, for example, when you open a TAB page, you create a process that can have multiple threads, such as a rendering thread, a JS engine thread, an HTTP request thread, and so on. When you make a request, you create a thread that can be destroyed when the request ends.

Browser kernel

The browser kernel is multi-threaded. Under the control of the kernel, threads cooperate with each other to keep synchronized. A browser usually consists of the following resident threads:

  • GUI rendering thread

  • JavaScript engine threads

  • Timing trigger thread

  • Event trigger thread

  • Asynchronous HTTP request threads

GUI rendering thread

  • Mainly responsible for page rendering, parsing HTML, CSS, building DOM tree, layout and drawing, etc.

  • This thread is executed when the interface needs to be redrawn or when a backflow is caused by some operation.

  • The thread is mutually exclusive with the JS engine thread. GUI rendering is suspended when the JS engine thread executes, and the main thread performs GUI rendering only when the task queue is idle.

JavaScript engine threads

  • The thread is of course primarily responsible for processing JavaScript scripts and executing code.

  • It is also mainly responsible for the execution of events ready to be executed, that is, when the timer count ends, or the asynchronous request succeeds and returns correctly, it will enter the task queue in turn and wait for the execution of the JS engine thread.

  • Of course, this thread is mutually exclusive with the GUI rendering thread, and when the JavaScript engine thread takes too long to execute the script, the page rendering will block.

Timing trigger thread

  • The thread responsible for executing functions such as asynchronous timers, such as setTimeout and setInterval.

  • When the main thread executes the code in turn, it will give the timer to the thread for processing. After counting, the event triggering thread will add the event after counting to the tail of the task queue and wait for the JS engine thread to execute.

Event triggered process

  • It is responsible for handing the prepared events to the JS engine thread for execution. Such assetTimeoutThe timer counts out,ajaxWhen the asynchronous request succeeds and triggers the return function, or the user triggers the click event, the thread will join the end of the task queue to wait for the EXECUTION of the JS engine thread.

Asynchronous HTTP request threads

  • A thread responsible for executing functions such as asynchronous requests, such as Promises, AXIos, Ajax, etc.

  • When the main thread executes the code in turn, it meets the asynchronous request and gives the function to the thread for processing. When the status code changes, if there is a callback function, the event-triggering thread will add the callback function to the tail of the task queue and wait for the JS engine thread to execute.

Event loops in browsers

Micro – Task and Macro – a Task

There are two types of asynchronous queues in browser-side event loops: Macro (macro task) queues and micro (micro task) queues. There can be multiple macro task queues and only one microtask queue.

  • Common macro-tasks include setTimeout, setInterval, script, I/O, UI rendering, etc.

  • Common micro-tasks include: New Promise().then(callback), MutationObserver (new HTML5 feature), etc.

Event Loop Process parsing

  • When the execution stack is empty, we can think of the execution stack as a stack structure that stores function calls, following the principle of first in, last out. The micro queue is empty, and the Macro queue has one and only one script.

  • The global context (script tag) is pushed onto the execution stack to synchronize code execution. During execution, the task is determined to be synchronous or asynchronous, and new macro-tasks and micro-tasks can be generated by calling some interfaces, which are pushed to their respective task queues. The script will be removed from the macro queue when the synchronized code is finished. This process is essentially the execution and dequeuing of the macro task in the queue.

  • In the previous step, we assigned a macro-task. In this step, we dealt with a micro-task. But it’s important to note that when Macro-Task is out, tasks are executed one by one; Micro-tasks, on the other hand, are executed in teams. So. As we process the micro queue, we execute the tasks in the queue one by one and de-queue them until the queue is empty.

  • Perform render operations to update the interface.

  • Check whether a Web Workder task exists and process it if so.

  • The process repeats until both queues are empty.

To summarize, each cycle is a process like this:

When a macro task completes, it checks to see if there is a microtask queue. If yes, all the tasks in the microtask queue are executed first. If no, the first task in the macro task queue is read. During the execution of the macro task, microtasks are added to the microtask queue one by one. When the stack is empty, the tasks in the microtask queue are read again, and so on.

  Promise.resolve().then(() = > {
    console.log('Propmise1')

    setTimeout(() = > {
      console.log('setTimeout2')},0)})setTimeout(() = > {
    console.log('setTimeout1')

    Promise.resolve().then(() = > {
      console.log('Promise2')})},0)
Copy the code

The final output is Promise1, setTimeout1, Promise2, setTimeout2

  • The macro task setTimeout2 is generated as the macro task setTimeout2 is generated as the macro task setTimeout2 is generated as the macro task setTimeout2 is generated as the macro task setTimeout2 is generated as the macro task setTimeout2

  • Then go to the macro task queue, macro task setTimeout1 before setTimeout2, macro task setTimeout1, output setTimeout1

  • When macro task setTimeout1 is executed, the microtask Promise2 is generated and added to the microtask queue. Then, all tasks in the microtask queue are emptied and Promisee2 is output

  • After clearing all tasks in the microtask queue, it goes to the macro task queue again, this time using setTimeout2