1. Processes and threads

A process is a dynamic process, an active entity. Simply put, the running of an application can be thought of as a process, and threads are the actual task performers in the running. You can say that a process contains multiple threads that can run simultaneously.

One of the hallmarks of the JavaScript language is single-threaded, which means you can only do one thing at a time. So why can’t JavaScript have multiple threads? It improves efficiency.

The single thread of JavaScript, relative to its purpose. As a browser scripting language, JavaScript’s primary purpose is to interact with users and manipulate the DOM. This means that it has to be single-threaded, which can cause complex synchronization problems. For example, if there are two threads of JavaScript at the same time, one thread adds content to a DOM node, and the other thread removes that node, which thread should the browser use?

In order to make use of the computing power of multi-core CPU, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the child threads are completely controlled by the main thread and cannot operate DOM. So, this new standard doesn’t change the single-threaded nature of JavaScript.

2. Synchronous and asynchronous

Single threading means that all tasks need to be queued until the first one is finished before the next one can be executed. If the first task takes a long time, the second task has to wait forever.

If the queue is due to a large amount of computation and the CPU is too busy, it is fine, but many times the CPU is idle because the IO devices (input and output devices) are slow (such as Ajax operations reading data from the network) and have to wait for the results to come out before executing.

The designers of the JavaScript language realized that the main thread could simply ignore the IO device, suspend the pending task and run the next one first. Wait until the IO device returns the result, then go back and continue the pending task.

Thus, all tasks can be divided into two types, synchronous and asynchronous.

Synchronization: A task that is queued to be executed on the main thread can be executed only after the previous task is completed.

Sequential execution;

Blocking;

** Asynchronous ** : Asynchronous tasks that do not enter the main thread but enter the task queue will be executed only when the task queue notifies the main thread that an asynchronous task is ready to execute.Copy the code

Using asynchronous scenarios:

(1) Scheduled task, setTimeout, setInterval

(2) Network request: Ajax request, dynamic loading

(3) Event binding, click and other interactive events

3. Task queue

Asynchronous task operation mechanism: 1. All synchronous tasks are executed on the main thread, forming an execution stack. 2. As long as the asynchronous operation completes the task queue queue 3, once all of the execution stack synchronization task to complete, the system will read task queue in order of the asynchronous task, so wait state is read asynchronous task ends, into the execution stack, executed 4, the main thread to repeat the above step 3. The main thread reads events from the “task queue” in a continuous Loop, so the whole operation mechanism is also called an Event Loop.

The main thread and the task queue are shown below.

Whenever the main thread is empty, it reads the “task queue”, and that’s how JavaScript works. The process repeats itself.

4. Events and callback functions

A “task queue” is a queue of events (also known as a message queue). When an IO device completes a task, it adds an event to the “task queue”, indicating that the related asynchronous task can be placed on the “execution stack”. The main thread reads the “task queue”, which is to read what events are in it.

In addition to the IO device events, the “task queue” includes some user-generated events (such as mouse clicks, page scrolling, and so on). As long as the callback function is specified, these events are queued up for the main thread to read.

Callbacks are code that is suspended by the main thread. Asynchronous tasks must specify a callback function, which is executed when the main thread starts executing an asynchronous task.

A “task queue” is a first-in, first-out data structure in which the first events are read by the main thread first. The reading of the main thread is basically automatic. As soon as the stack is emptied, the first event in the “task queue” is automatically sent to the main thread. However, due to the “timer” function mentioned later, the main thread first checks the execution time, and certain events cannot be returned to the main thread until the specified time.

5, the Event Loop

The main thread reads events from the “task queue” in a continuous Loop, so the whole operation mechanism is also called an Event Loop.

To better understand the Event Loop, see the following diagram.

In the figure above, when the main thread is running, the heap and stack are created, and the code in the stack calls various external apis, which add various events (click, load, done) to the “task queue”. As soon as the stack completes, the main thread reads the “task queue” and executes the corresponding callback function for those events.

6. Micro tasks, macro tasks

Each iteration of an event loop is called a tick. There are macrotasks and microtasks, and when each Macro Task is finished, you should clean up all the microtasks.

Macro task macrotask

Including: Script, setTimeout, setInterval, I/O, UI interaction events, setImmediate(Node.js environment)

Microtasks (special tasks) Microtasks

Includes: Promise, MutaionObserver, process.nexttick (node.js environment)

In Js, there are two types of task queues: Macro tasks and micro tasks. There can be multiple macro task queues and only one microtask queue.

Order of execution: JS engine will divide all tasks into these two queues according to their categories. (1) Take out the first task from the macro task queue (generally at the initial stage, there is only one scrip t(whole code) task in the macro task queue) (2) take out all tasks in the micro task queue and execute them in sequence after completion of execution. (3) Then take out the macro task. The cycle continues until both queues run out of tasks.

Console. log('script start') // The first asynchronous task setTimeout(()=>{console.log('setTimeout')},0) // the second asynchronous task Promise.resolve().then(()=>{ console.log('promise1') }).then(()=>{ console.log('promise2'); }) console.log('script end')Copy the code

Analysis of the previous examples shows that:

  1. Execute the main function for the first time, outputscript start
  2. encountersetTimeout, the corresponding callback is insertedmacrotask queue
  3. encounterpromise, the corresponding callback is insertedmicrotask queue
  4. The outputscript end, the main function is finished, the stack is cleared, and the check beginsmicrotask queueFind runnable tasks inside, so output them in orderpromise1andpromise2
  5. microtask queueAfter execution, start a new loop frommacrotask queueTake out thesetTimeoutTask and execute, outputsetTimeout
  6. The end renders the output above.