preface

This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.

JavaScript only has one thread that executes code in the browser. If we compare threads to people, we can imagine that only one person is executing a task. If there are multiple tasks, then you need to queue up to execute them one by one. The advantage of this mode is that it is safer and simpler, but the disadvantage is obvious: if there is a particularly time-consuming task, other tasks must wait for that task to complete, and then there will be a case of suspended animation. To solve this situation, JS designs two modes, synchronous mode and asynchronous mode.

Synchronous mode

In synchronous mode, the tasks to be executed are executed in sequence, and the latter task can be executed only after the former task is completed. The order of execution of the program is the same as the order of execution of the code, which looks relatively simple. Let’s look at a simple synchronization code:

  console.log('globalBegin')

  function bar () {
    console.log('bar')}function foo () {
    console.log('foo')
    bar()
  }

  foo()

  console.log('globalEnd')
Copy the code

First, the JS engine pushes our entire code onto the call stack as an anonymous call. Then it executes the JS code line by line, starting with console.log. The engine pushes console.log onto the call stack. In the console output globalBegin\color{#FF0000}{output globalBegin} output globalBegin and pop console.log in the call stack. The first line in foo is console.log, so console.log is executed on the call stack. The console outputs foo\color{#FF0000}{output foo} and pops up console.log. The second line of foo is a call to bar, which needs to be pushed onto the call stack. Console output bar\color{#FF0000}{output bar} output bar, bar function completed, pop-up bar call, then the call stack pop-up foo call, finally execute console.log, GlobalEnd \color{#FF0000}{globalEnd} globalEnd.

Asynchronous mode

In asynchronous mode, time-consuming tasks can be executed immediately without waiting. Time-consuming tasks are defined in the form of callback functions. The callback function is automatically executed after the time-consuming tasks are completed. For example, if your immediate task is to boil the water for 15 minutes, clean for 10 minutes, walk the dog for 10 minutes, you can boil the water first and not wait for the boil to finish. It takes 20 minutes to do the cleaning and then walk the dog. If it takes 35 minutes to do it simultaneously, the efficiency is greatly reduced. Let’s look at the code for details:

  console.log('global begin')

  setTimeout(function timer1 () {
  console.log('timer1 invoke')},1800)

  setTimeout(function timer2 () {
    console.log('timer2 invoke')
    setTimeout(function inner () {
      console.log('inner invoke')},1000)},1000)
  console.log('global end')
Copy the code

In asynchronous mode, there is not only the Call stack, but also the concept of Web APIs, queues and Event loops. Just like in synchronous mode, the JS engine will push our entire code into the Call stack as an anonymous call. The js engine pushes console.log onto the call stack, prints global begin in the console, and pops console.log in the call stack. Next comes the first setTimeout, pushing the first setTimeout onto the call stack, starting a countdown timer for Timer1 in the Web APIs, and popping the first setTimeout. Then a second setTimeout, push this setTimeout onto the call stack, start a timer for Timer2 in the Web APIs, and pop this setTimeout. Then go to the last line, press console.log, print global end, and console. At this time there is no task to execute in the anonymous call, the anonymous call pops up, and the call stack is cleared. When the stack is empty, the Event loop starts executing and puts the callbacks of the Queue into the stack. The Queue is empty (the fastest callbacks need to be executed after one second in web APIs). After 1 second, the timer2 callback is pressed to Queue, the Event loop is executed, the Timer2 callback is pressed to call stack, the console prints Timer2 invoke, and presses inner into the Web APIs. 0.8 seconds later, The timer1 callback is pressed to Queue, the Event loop is executed, the Timer1 callback is pressed to call stack, the console prints Timer1 invoke, 0.2 seconds later, the inner callback is pressed to Queue, the Event loop is executed, The inner callback function is pushed onto the call stack, and the console prints the Inner invoke.

The specific asynchronous process can be seen in the following figure:

There is an asynchronous calling thread in the diagram, and some readers may wonder if this JS is not a single thread. Javascript is single threaded, the green thread at the top is the JS thread, but browsers are not single threaded, some web APIs that JS calls are not single threaded, by single threaded we mean our code is single threaded, and some Web APIs use their own threads to perform asynchronous operations, The runtime environment provides apis that work in either synchronous or asynchronous mode.