The callback

The function that you write but don’t call, that you give someone else to call is a callback that calls the function back

function f1(){}
function f2(fn){
  fn()
}
f2(f1)
Copy the code

The F1 of the above code is the callback

Because I only created it, INSTEAD of calling it, F2 called it

Asynchrony and callback

  • Asynchronous tasks require callback functions to notify the result
  • However, callbacks need not only be used in asynchronous tasks
  • Callbacks can be used in synchronization for example
array.forEach(n= >console.log(n)) // This is a synchronous callback
Copy the code

Callback hell

Why is there callback hell? I will illustrate with the following examples

Read a, B, and C files in no order

const fs = require('fs')

fs.readFile('./a.txt'.'utf8'.function (err, data) {
    if (err) {
        // return console.log(' read error ');

        // Throw an exception
        2. Print the error message to the console
        throw err
    }
    console.log(data);
})
fs.readFile('./b.txt'.'utf8'.function (err, data) {
    if (err) {
        // return console.log(' read error ');

        // Throw an exception
        2. Print the error message to the console
        throw err
    }
    console.log(data);
})
fs.readFile('./c.txt'.'utf8'.function (err, data) {
    if (err) {
        // return console.log(' read error ');

        // Throw an exception
        2. Print the error message to the console
        throw err
    }
    console.log(data);
})

Copy the code

The data printed here is in no order, whoever is faster will be executed first.

PS F:\nodejs\Node_test> node .\13. Js hello aaaa hello BBBB hello CCCC PS F:\nodejs\Node_test> node.\ 13 Js hello aaaa hello CCCC hello BBBB PS F:\nodejs\Node_test> node.\ 13 Js hello aaaa hello CCCC hello BBBBCopy the code

If you want to read a, B, and C sequentially

const fs = require('fs')

fs.readFile('./a.txt'.'utf8'.function (err, data) {
    if (err) {
        // return console.log(' read error ');

        // Throw an exception
        2. Print the error message to the console
        throw err
    }
    console.log(data);
    fs.readFile('./b.txt'.'utf8'.function (err, data) {
        if (err) {
            // return console.log(' read error ');

            // Throw an exception
            2. Print the error message to the console
            throw err
        }
        console.log(data);
        fs.readFile('./c.txt'.'utf8'.function (err, data) {
            if (err) {
                // return console.log(' read error ');

                // Throw an exception
                2. Print the error message to the console
                throw err
            }
            console.log(data); })})})Copy the code

I just need to nest layer by layer, and then execute B.txt after reading A.txt, and then execute C.txt after reading B.txt

PS F:\nodejs\Node_test> node .\13. Js hello aaaa hello BBBB hello CCCC PS F:\nodejs\Node_test> node.\ 13 Js hello aaaa hello BBBB hello CCCC PS F:\nodejs\Node_test> node.\ 13 Js hello aAAA hello BBBB Hello CCCCCopy the code

Therefore, sequential reading of files in asynchronous operations requires nested callback functions, but such code looks messy and low maintenance

To solve this problem, this is where we need to use promise

Promise

Reference documents: Ruan Yifeng and Promise MDN

Why do we need promise?

My personal understanding is three points:

  1. When using Ajax to call successful and failed methods, naming is not canonical enough.
  2. Prone to callback hell
  3. Error handling is difficult
  4. To solve the asynchronous

What is promise?

Print it out and see:

Obviously, promise is a constructor. It has resolve, Reject, all, race, etc., and then, catch, etc., the most commonly used methods in the prototype. Therefore, there must be “then” and “catch” methods in new promise.

How do I create a Promise

function runAsync() {
  const p = new Promise((resolve, reject) = > {
    // Asynchronous operation
    setTimeout(() = > {
      console.log('Executed successfully');
      resolve('data')},1000)})return p
}

runAsync()
Copy the code

Where the Promise constructor takes one argument, which is the function. Two arguments are passed: resolve, reject. Represents the callback function after the asynchronous operation succeeds and the callback function after the asynchronous operation fails.

We’ll wrap a function, put a promise in it and return it, so we can use the then,catch method from the promise prototype

runAsync().then(function(data){
    console.log(data);
    // You can do some other things with the data
});
Copy the code

Results show

That’s where Promise comes in. In a nutshell, it’s the ability to separate the writing of the callback and execute it as a chain operation after the asynchronous operation.

Promise. All usage

The ALL method provides the ability to execute asynchronous operations in parallel and not execute callbacks until all asynchronous operations have completed.

Look at the following example:

function runAsync1() {
  const p = new Promise((resolve, reject) = > {
    // Asynchronous operation
    setTimeout(() = > {
      console.log('Executed successfully');
      resolve(Data '1')},1000)})return p
}

function runAsync2() {
  const p = new Promise((resolve, reject) = > {
    // Asynchronous operation
    setTimeout(() = > {
      console.log('Executed successfully');
      resolve(Data '2')},1500)})return p
}

function runAsync3() {
  const p = new Promise((resolve, reject) = > {
    // Asynchronous operation
    setTimeout(() = > {
      console.log('Executed successfully');
      resolve('data 3')},2000)})return p
}


Promise
  .all([
    runAsync1(),
    runAsync2(),
    runAsync3()
  ])
  .then(result= > console.log(result))
Copy the code

We execute with promise.all, and we take three arrays of values that return Promise objects, and then these three asynchronous operations execute in parallel, and when they’re all done, the data will be in the then method. That is, the all method puts the results of all asynchronous operations in a generic pig and passes them to THEN.

Promise. Race usage

The usage is the same as promise.all, except that the all method executes a callback based on the slow runner, whereas the race method executes a callback based on the fast runner

Replace the all method of the code shown above with race and see what happens

Promise
  .race([
    runAsync1(),
    runAsync2(),
    runAsync3()
  ])
  .then(result= > console.log(result))
Copy the code

Look! It will prioritize the fastest (1s) runAsync1 output,

Because of asynchronous processing problems, the data in runAsync1 does not wait for the above Promise execution to finish before it starts, so ‘data 1’ is printed first due to time delays.