JS asynchronous execution principle and callback details

JS asynchronous execution principle and callback details

1. JS asynchronous execution principle

We know that JavaScript is single-threaded, while browsers are multi-threaded. Single-threaded execution tasks need to be queued one by one. If a task takes a long time to execute (such as ajax takes a long time), it will directly lead to no response, and the subsequent tasks will be waiting for execution. This is when asynchrony comes into play.

To understand asynchrony, we first need to know that the browser has three basic resident threads: JS engine thread, event triggering thread, and GUI rendering thread.

The JS engine thread and the event triggering thread together constitute an event loop mechanism, and the GUI rendering thread and the JS engine are mutually exclusive. When the JS engine is executed, the GUI thread will be suspended, and the GUI updates will be saved in a queue and executed immediately when the JS engine is idle.

We analyze it from its event loop mechanism:

The JS engine thread is divided into synchronous and asynchronous tasks:

1. All synchronization tasks are executed through the main thread to form an execution stack.

2. When there is an asynchronous task, it is handed over to the asynchronous process (WebAPIs): including event triggering thread or timer thread processing to form a task queue.

3. When all tasks in the execution stack are processed and the main thread is idle, tasks will be extracted from the task queue and executed in the execution stack.

In layman's terms, in addition to the main thread, JavaScript also has a task queue. The task queue stores content that needs to be executed asynchronously. After the main thread is executed, it will continuously scan and execute tasks in the task queue until the queue is empty.

Picture explanation:

As shown in the picture, Xiao Ming puts learning into the asynchronous task queue because learning takes a long time and he will not be able to play the DNF game if he does not finish it. He will study (task queue) after finishing the game (main thread). During this period, the mother adds learning events (DOM events). Every time Xiao Ming completes a learning task, he checks to see what other tasks there are (loop scanning) until he finishes it.

Let's look at another example (the browser refreshes and clicks the button continuously):

  let myData = null
  //ajax request function ajax() {
  //Tencent COVID-19 real-time data interface, for learning only axios.get('https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=chinaDayList,chinaDayAddList,nowConfirmStatis,provinceCompare')
   .then(data => {
   console.log("ajax returns successfully");
   myData = data.data
   console.log(myData);

   })
   .catch(error => {
   console.log("ajax return failed");
   })
  }
  console.log(myData);
  ajax()
  setTimeout(() => {
  console.log('timer');
  }, 2000);
  console.log(myData);
  const btn = document.querySelector('button')
  btn.onclick = () => {
  console.log("clicked");
  }

null
null
ajax returns success
Object
Clicked the timer clicked

As you can see, the console is executed synchronously in the main thread and is executed first, while the task queue outside the main thread stores the asynchronously executed content, which is setTimeout, ajax and DOM events, which are executed in the order of the task queue (loop scanning queue).

Why do we need to scan in a loop?

It can be seen from the click event that when the user interacts (click events, scroll events, window size change events, etc.), new events are added to the task queue in the event loop and then wait for execution, so a cyclic scan is required.

2. Callbacks in JS Asynchrony

Since asynchronous operations are all executed in the last task queue, many of our logics are difficult to implement. At this time, we need to handle this asynchronous logic. The most common way is callback - calling back.

Callback function: To put it simply, when function A passes function B as a parameter, function B becomes the callback function executed by function A. There are two types of callbacks: nested callbacks and chained callbacks.

Here is a simple usage of callback:

   let myData = null
   console.log(myData);
   setTimeout(() => {
    console.log('timer');
   }, 2000);
   const btn = document.querySelector('button')
   btn.onclick = () => {
    console.log("clicked");
   }
   let name = "Zhang San"
   function hr(callback) {
    setTimeout(() => {
     console.log(`I am ${name}`);
     callback();
    }, 2001);
   }
   console.log(myData);
   function gj() {
    console.log(`${name} Hello, I'm Li Si, let's get to know each other`);
   }
   hr(gj)

null
null
Clicked the timer. I am Zhang San. Hello, I am Li Si. Let’s get to know each other. Clicked

It is obvious that when our function needs to use data, a callback is used. Here, an asynchronous callback is used.

Although callback is a common method to solve asynchrony, it is accompanied by increasingly complex requirements of JS. Synchronous and asynchronous require more and more callbacks to implement logic. The mixture of synchronous and asynchronous operations and excessive callback nesting and indentation make the code difficult to interpret and maintain, forming a "callback hell".

Let’s look at an example:

const verifyUser = function(username, password, callback){
  dataBase.verifyUser(username, password, (error, userInfo) => {
    if (error) {
      callback(error)
    }else{
      dataBase.getRoles(username, (error, roles) => {
        if (error){
          callback(error)
        }else {
          dataBase.logAccess(username, (error) => {
            if (error){
              callback(error);
            }else{
              callback(null, userInfo, roles);
            }
          })
        }
      })
    }
  })
};

Most people will get a brain freeze just by looking at the code above. If a project has hundreds of such code blocks, after a while, I believe even the person who wrote it will have a headache. Coming to my own project is like coming to hell.

The most important thing is that at the same time, there is a trust issue with the callback, as it gives execution control to a third party (such as ajax). In order to solve the trust problem, we must write various logics in the program to solve the trust problem caused by callbacks.

Calling too early

·Call completed

The number of calls is too many or too few, and the required parameters are not successfully passed to the callback function.

Possible errors are swallowed.

It can be found that writing specific logic to solve specific trust problems has made the difficulty greater than the application value itself, and it will also cause problems such as redundant code and poor readability.

In summary: callbacks solve asynchronous problems:

1) It does not conform to people’s logical thinking in task processing

2) Trust issues caused by callbacks.

Faced with the increasingly obvious drawbacks of callbacks, ES6 updated Promise to solve asynchronous problems. The next article will write about ES6——Promise.

Summarize

This is the end of this article about JS asynchronous execution principle and callback. For more relevant JS asynchronous execution principle callback content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of asynchronous process implementation in single-threaded JavaScript
  • Analyze the characteristics of JS single-threaded asynchronous io callback
  • Javascript asynchronous programming: Do you really understand Promise?
  • Detailed explanation of the initial use of Promise in JavaScript asynchronous programming
  • How to write asynchronous tasks in modern JavaScript
  • Detailed explanation of asynchronous generators and asynchronous iterations in Node.js
  • Learn asynchronous programming in nodejs in one article
  • Detailed explanation of asynchronous programming knowledge points in nodejs
  • A brief discussion on the three major issues of JS: asynchrony and single thread

<<:  mysql5.7.18 decompressed version to start mysql service

>>:  Rsync+crontab regular synchronization backup under centos7

Recommend

How to implement distributed transactions in MySQL XA

Table of contents Preface XA Protocol How to impl...

How to reduce image size using Docker multi-stage build

This article describes how to use Docker's mu...

Implementation of building custom images with Dockerfile

Table of contents Preface Introduction to Dockerf...

React Diff Principle In-depth Analysis

Table of contents Diffing Algorithm Layer-by-laye...

HTML markup language - form

Click here to return to the 123WORDPRESS.COM HTML ...

Let's talk briefly about the changes in setup in vue3.0 sfc

Table of contents Preface Standard sfc writing me...

Vue large screen display adaptation method

This article example shares the specific code for...

MySQL Basics Quick Start Knowledge Summary (with Mind Map)

Table of contents Preface 1. Basic knowledge of d...

Detailed explanation of Strict mode in JavaScript

Table of contents Introduction Using Strict mode ...

The principle and application of ES6 deconstruction assignment

Table of contents Array destructuring assignment ...

MySQL master-slave replication delay causes and solutions

Table of contents A brief overview of the replica...