Javascript is a single-threaded language in which code execution is queued from top to bottom. That is, only one task can be executed at a time. If a task takes too long, the execution of subsequent tasks will be blocked, for example, causing the browser to suspend execution. To solve this problem, asynchronous execution is required.

This article focuses on how asynchrony is implemented. Before explaining asynchrony, you need to understand the synchronization mechanism.

Execute the following code:

// Process datafunction processImage() {
 console.log("Image processing completed"} // Request datafunction networkRequest() {
   console.log("Data request successful")
   greeting()
}

function greeting() {
  console.log("Hello World!")
}

processImage()
networkRequest()
Copy the code

Executing this code requires understanding two concepts: the execution context and the execution stack.

Execution Context

In JavaScript, an execution context is created when code is run. Global code has a global execution context, and each method has its own execution context.

Call Stack

The call stack is the place where JavaScript is run. The execution context is not executed until it is loaded onto the stack. After execution, it is ejected, following the first in, last in, first out principle.

With these two concepts in mind, let’s see how this code executes:

The main() global execution context is the first to be pushed onto the stack. Each method is pushed onto the stack as it executes, and when main() pops up, the entire code completes execution. It’s easy to see that any method that takes a long time to execute will block the entire stack (or thread).

How to solve it? Introducing asynchronous execution, of course

Let’s look at some code that executes asynchronously:

const networkRequest = (a)= > {
  const callback = (a)= > console.log('Async Code');
  setTimeout(callback, 2000);
};
console.log('Hello World');
networkRequest();
// => 'Hello World'
/ / wait for 2 s
// => 'Async Code'
Copy the code

We use setTimeout to simulate interface requests. Note that setTimeout is not Javascript, it is an API provided by the browser (node.js also has this API).

When setTimeout is reached, it is handed over to the browser-provided thread for execution. Console. log(‘Hello World’) will continue execution, and does not wait for setTimeout to finish execution, which forms asynchronous execution.

When setTimeout is complete, the callback is pushed to the Message Queue. The Event Loop watches to see if The Call Stack empties, and if so, pushes The callback onto The Stack. Here’s a GIF:

conclusion

SetTimeout, Promise, Async/Await, etc., can be realized asynchronously. It should be noted that ES6 has joined the Micro Task Queue in order to introduce Promise, which has a higher priority than Message Queue. In other words, when The call stack is empty, The Event Loop will be The first to execute The microtask queue callback on The stack, as shown in The following code:

function func() {
	setTimeout((a)= >{console.log('setTimeout')}, 0)
	new Promise((resolve, reject) = >{
		resolve('Promise')
	}).then((msg) = > {console.log(msg)})
}
func()
// => Promise
// => setTimeout
Copy the code

Although the setTimeout code executes before the Promise, the printout shows that the Promise callback executes before setTimeout.

Reference

  • Understanding Asynchronous JavaScript

  • Four approaches to Asynchronous programming in Javascript