Promise basic

  1. Promise: A new solution for asynchronous programming introduced in ES6.

    Promises are mainly to solve the previous problem of callback hell. Promise is a constructor that encapsulates an asynchronous operation and can get its success or failure result.

    Promise accepts a function parameter, this function parameter has two formal parameters, the first is success (resolved by default), and the second is failure (reject by default). When calling resolve() Promise takes the success path, calling reject() takes the failure path.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //Instantiate a Promise object
    const p = new Promise(function(resolve, reject){ //resolve & reject. It's just an unspoken rule, you can name it yourself
    setTimeout(function(){
    let data = 'obj in database';
    if(Math.random()>0.5){
    resolve(data); //custom 'success'
    }else{
    reject(data); //custom 'failure'
    }
    }, 1000);
    });

    After success or failure, the then() method of the Promise object can be called. The then() method accepts two function-type parameters. Both function parameters have formal parameters. The successful formal parameter is generally called value, and the failed formal parameter is generally called reason.

    1
    p.then(function(value){}, function(reason){})
    1. The first function argument in then() is called when the Promise status is fulfilled. where value is the parameter of the previous resolve().

      1
      2
      3
      p.then(function(value){
      console.log(value) //The value value is the parameter passed in by resolve() in the previous Promise
      }, function(reason){})
    2. When the Promise status is rejected, the second function argument in then() is called. where the reason value is the parameter of the previous reject().

      1
      2
      3
      4
      p.then(function(value){ 
      },function(reason){
      console.log(reason) //The reason value is the parameter passed in by reject() in the previous Promise.
      })

  2. Promise encapsulates an example of an Ajax request.

    Ajax request for JS in ES5

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const xhr = new XMLHttpRequest(); //The first step: create an object
    xhr.open("GET","http://api.apiopen.top/getJoke"); //Part 2: Initialization
    xhr.send(); //The third step: send
    xhr.onreadystatechange = function(){ //Step 4: Bind events and process response results
    if(xhr.readyState === 4){
    if(xhr.status >= 200 && xhr.status < 300){
    console.log(xhr.response); //Processing successful results
    }else{
    console.error(xhr.status); //Process the result of failure
    }
    }
    }

    Encapsulating Ajax with Promises

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    const p = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET","http://api.apiopen.top/getJoke");
    xhr.send();
    xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
    if(xhr.status >= 200 && xhr.status < 300){
    resolve(xhr.response); //Declare success first, and pass parameters to then() before processing
    }else{
    reject(xhr.status); //Declare failure first, and pass parameters to then() before processing
    }
    }
    }
    })

    // Specify success/failure callback
    p.then(function(value){
    console.log(value) //Success, pass in the parameter xhr.response of resolve() as the actual parameter of the formal parameter value.
    },function(reason){
    console.err(reason) //If it fails, pass in the parameter xhr.status of reject() as the actual parameter of the formal parameter reason.
    })

    This example shows that Promises handle asynchronous success/failure results differently than in ES5. It turns out that ES5 operates in the callback function, and now the callback is specified by the then() method after the asynchronous task. This is clearly structured and doesn’t create callback hell problems.


  3. then() function

    Promise instances have a then() method, that is, the then() method is defined on the prototype object Promise.prototype. Parameter 2 is optional. The return result of then() is also a Promise object.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const p = new Promise((resolve, reject) => {
    setTimeout(() => {
    reject('ERROR!')
    }, 1000)
    })

    const result = p.then(value => {
    console.log(value)
    }, reason => {
    console.warn(reason)
    })

    console.log(result); //The result is a Promise object, and the result is resolved/fulfilled (new version)

    The return result of the then() method The state of the Promise object is determined by the execution result of the callback function.

    1. If the result returned in the callback function is non promise type data, status is success, and the return value is the success value of the object.

      1
      2
      3
      4
      5
      6
      7
      8
      const result = p.then(value => {
      console.log(value)
      return 'success!';
      }, reason => {
      console.warn(reason)
      })

      console.log(result); //The status of the result is 'resolved' and the value is 'success!'.

      When no return is written, the default return result inside the function is undefined. undefined is not a Promise type object, so the return status result is also success.

      1
      2
      3
      4
      5
      6
      7
      8
      const result = p.then(value => {
      console.log(value)
      //return 'success!'; no return
      }, reason => {
      console.warn(reason)
      })

      console.log(result); //The status of the result is 'resolved' and the value is undefined.

    2. If the result returned in the callback function is a promise object, the state returned by the internal promise object determines the return of the then() method The state of the promise, and the value of the internal promise is the value of the promise returned by the then() method.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      const result = p.then(value => {
      console.log(value)
      return new Promise((resolve, reject) => { //The return status of this promise determines the status of the promise returned by the then() method.
      resolve('ok');
      })
      }, reason => {
      console.warn(reason)
      })

      console.log(result); //The status of the result is 'resolved' and the value is 'ok'.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      const result = p.then(value => {
      console.log(value)
      return new Promise((resolve, reject) => { //reject, similarly
      reject('error');
      }, reason => {
      console.warn(reason)
      })

      console.log(result); //The status of the result is 'rejected' and the value is error.

    3. If an error is thrown, then() returns a promise with a status of rejected and value as the value of the thrown error. Note that throw new Error('test'); and reject(new Error('test')); are equivalent.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      const result = p.then(value => {
      console.log(value)
      throw new Error('Error diagnosis') //Throwing an error, there is a throw, such as throw 'ERROR'; also acceptable.
      })
      }, reason => {
      console.warn(reason)
      })

      console.log(result); //The status of the result is 'rejected' and the value is 'Error diagnosis'.

  4. The chained invocation of the then() method, and the reason parameter can be omitted

    1
    2
    3
    4
    p.then(value => {
    }).then(value => {
    }).then(value => {
    })

    Callback hell can be avoided by chaining calls.


    Chain call example: Each call passes in new data and saves all data on the chain.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const p = new Promise((resolve, reject) => {    //The first promise on the chain
    fs.readFile("./resources/file1.md", (err, data) => { //node.js syntax
    resolve(data);
    });
    });

    p.then(value => { //The 2nd promise on the chain
    return new Promise((resolve, reject) => {
    fs.readFile("./resources/file2.md", (err, data) => {
    resolve([value, data]); //The value is the data of file1, and the data is the data of file2.
    });
    });
    }).then(value => { //The 3rd promise on the chain。Note that value here is the resolve value of the second promise on the chain:[value, data], which is the data of file1 and file2.
    return new Promise((resolve, reject) => {
    fs.readFile("./resources/file3.md", (err, data) => {
    value.push(data);
    resolve(value);
    });
    });
    }).then(value => { //The value value is the content (array of) of the first three files
    console.log(value.join('\r\n')); //combine
    })

    Break the Promise chain

    In promise chains without catch(), each then() on the chain has two function arguments, success and failure. But note that whether it succeeds or fails (return non-Promise, return a successful Promise, throw an error), it will trigger then() on the next chain.

    If you want to end the chain call directly after a then() in the chain fails to trigger, you need to call a Promise instance with a initialized state in the then() failure function.

    1
    return new Promise(() => {});

  5. catch()

    Promise.prototype.catch() is syntactic sugar for .then(null, rejection), catch() method is used to specify the callback of Promise failure, which can uniformly handle errors on the Promise chain. Even if catch() is used, all then()s in the chain do not need to write failure callbacks.

    1
    2
    3
    4
    5
    const p = new Promise((resolve, reject) => {    
    setTimeout(() => {
    reject("Error!");
    }, 1000)
    });
    1
    2
    3
    p.then(function(value){}, function(reason){   //Method 1: Specify the failed callback through then()
    console.error(reason)
    })
    1
    2
    3
    p.catch(function(reason){    //Method 2: Specify the failure callback through catch(). Use the first value argument to write then().
    console.error(reason)
    })

  1. Micro task, Macro task

    The code in new Promise(), except asynchronous code and resolve, will be executed directly in synchronous order. And resolve will be put into the micro task queue, so it will be executed after the synchronous code is executed.

    The code in promise.then() is asynchronous and placed in the micro task queue. So the execution order is after the synchronous code.

    And promise only has three states: pending, fulfilled, rejected. Therefore, as long as resolve or reject is encountered, the state will be condensed, and the following fulfilled, rejected, if any, will not be executed. But if there is other code behind the resolve or reject code, such as console.log(), then this part of the code will continue to be executed synchronously.

    If the promise is pending, neither .then() nor .catch() will execute.


    If there are two asynchronous tasks, one is a micro task such as promise, and the other is a macro task such as setTimeout, then the micro will be executed first, and then the macro will be executed. Therefore, the code execution order is, synchronization > micro task > macro task. At the same time, after each macro task or micro task is executed, the system will recheck the macro task queue and macro task queue. Therefore, newly generated tasks with high priority will be executed first.


Share