1. Before we talk about browsers and JavaScript, let’s take a quick look at processes and threads
Process: The smallest unit of resource allocation

A process is an execution instance of an application program and an independent unit of the operating system for resource allocation and scheduling.

Thread: The smallest unit of CPU scheduling

Thread is an execution unit within a process, which is a basic unit that is independently scheduled and dispatched by the system. Once the process is created, the system actually starts the main thread of execution that executes the process.

This may not be easy to understand, but let’s use the factory 🏭 model as an analogy:

  • The core of the computer is the CPU, which undertakes all the computing tasks. It is like a factory 🏭, always running.
  • A single CPU can only run one task at a time
  • Processes are like factory floors 🚗, representing individual tasks that the CPU can handle
  • In a workshop, there can be many workers 👷. They work together on a task
  • Threads are like workshop workers 👷, a process can contain multiple threads
2. Browser multithreading vs. Javascript single threading (single threading vs. multi-threading)

First, browsers are multithreaded, so browsers can handle multiple events at once, such as page rendering, script execution, event handling, etc.

JavaScript is single threaded (browsers assign only one thread to JS)

JavaScript single-threaded

The nature of single threads is that you can only process one thing at a time. The latter task can be executed only after the former task is complete.

JS in a single thread to achieve asynchronous mechanism as long as the browser task queue, task queue is divided into synchronous task queue and asynchronous task queue, asynchronous task can be divided into macro task and micro task

In synchronous top-down task execution, if you encounter an asynchronous task, not executed immediately, but put it in an asynchronous task queue to queue, when the synchronous after completion of task execution, will search to asynchronous task queue waiting for the contents of the task queue (synchronization task queue finish, whether or not an asynchronous task to time, don’t execute). Wait until the condition is reached, and then go to the asynchronous task queue to find. This is because JS is single-threaded and can only handle one thing at a time

Why is JavaScript designed to be single-threaded

The reason JavaScript is single-threaded, rather than multi-threaded, has to do with its history. JavaScript wasn’t as powerful as it is today. As a browser scripting language, it was primarily used to handle user interaction with pages and manipulation of the DOM. If JavaScript is multithreaded, assuming that there are two threads working on the DOM at the same time, the browser will not know which thread should process the result.

3. Synchronous and asynchronous tasks

Synchronization: Only one task can be done on a thread at a time. When the task is complete, the next task can be done.

Asynchrony: Executes a task in the main stack, but discovers that the task is an asynchronous operation and puts it in the asynchronous task queue.

Asynchronous tasks are divided into macro tasks and micro tasks:

Macro tasks: timer setTimeout, setInterval, event binding, callback function, FS module in Node

Microtasks: New Promise().then(callback), process.nexttick (), async await

4. Execution stack and task queue

1) Execution stack: As can be seen from the name, execution stack uses the stack structure of data structure. It is a stack structure that stores function calls and follows the principle of “first in, last out”. It is mainly responsible for keeping track of all the code to be executed. Whenever a function completes, it pops off the stack; If there is code that needs to be executed, push is done.

2) Task queue: It can be seen from the name that the task queue uses the queue structure in the data structure. It is used to store asynchronous tasks and follows the first-in, first-out principle. It is responsible for sending new tasks to a queue for processing.

Order of execution:

JavaScript executes code by placing synchronized code in order on the execution stack, and then executing the functions in turn. When an asynchronous task is encountered, it is put into the task queue, and after all the synchronous code in the current execution stack is completed, the callback of the completed asynchronous task is fetched from the asynchronous task queue and put into the execution stack to continue execution, and so on until all the tasks have been executed

The synchronization task is performed first, then the micro task is performed, and finally the macro task is performed. The process repeats itself

Here are some classic interview questions
console.log("script start");
​
async function async1() {
  await async2();
  console.log("async1 end");
}
​
async function async2() {
  console.log("async2 end");
}
​
async1();

setTimeout(function () {
  console.log("setTimeout");
}, 0);

new Promise((resolve) = > {
  console.log("Promise");
  resolve();
})
  .then(function () {
    console.log("promise1");
  })
  .then(function () {
    console.log("promise2");
  });

console.log("script end");
// script start => async2 end => Promise => script end => async1 end=> promise1 => promise2 => setTimeout

Copy the code

Resolution:

1. Execute the synchronization task first: print script start, async2 end, Promise, script end

2. After synchronization, perform microtasks such as Async1 end, promise1, and promise2

3. Finally, run the macro task setTimeout