Promise Quick Start

This article solves only three problems.
What is promise?
What's the use of promise?
How to use promise?

1. What is promise?

For ES6, it's a constructor that can use new Promise() to create Promise instances.

2. What's the use of promise?

Imagine two scenarios:

First, in business, you need to request two interfaces in the background, but you need to request the second interface after the first one returns the successful result. This may be written as follows.


    var request  = function(){
        var xhr1 = new XMLHttpRequest();
        xhr1.onreadystatechange = function(){
          if(xhr1.readyState !== 4){
            alert('The first step failed, please try again!');
            return;
          }
          if(xhr1.status === 200){
            console.log('The first step is successful. Let's start the next step.');
            var xhr2 = new XMLHttpRequest();
            xhr2.open("GET", url);
            xhr2.onreadystatechange = function(){
              if(xhr2.readyState !== 4){
                alert('The second step failed, please try again!');
                return;
              }
              if(xhr2.status === 200){
    
                //Something to do after two successful requests...
    
              } else {
                alert('The second step failed, please try again!');
              }
            };
            xhr2.responseType = "json";
            xhr2.setRequestHeader("Accept", "application/json2");
            xhr2.send();
          } else {
            alert('The first step failed, please try again!');
          }
        };
        xhr1.responseType = "json";
        xhr1.setRequestHeader("Accept", "application/json1");
        xhr1.send();
      });
    }
    
    request();

The above code implements two asynchronous requests with xhr objects, and the code is very long. But this is just a two-tier callback nesting. Imagine how terrible more asynchronous callback dependencies are.

Second, we all know that one of the characteristics of nodejs is event-driven, so we must use event callback function to deal with logic, and multi-layer nesting of callbacks is inevitable. Then your code will probably be written as this virtue.


    async(1,function(value){
      async(value,function(value){
        async(value,function(value){
          async(value,function(value){
            async(value,function(value){
              async(value,function(value){
                async(value,function(value){
                  async(value,function(value){
                    async(value,final);
                  });
                });
              });
            });
          });
        });
      });
    })

So you fall into the long ugly nested hell.

How?

Use promise.

How to use it?

Look down.

3. How to use promise?

While learning how to use Promise, you need to get in touch with several knowledge points about it from time to time. The best way to understand is to understand without using it.

The first thing to understand is that each Promise instance has three states:

1. pending in progress
2. Success resolution
3. Failure rejected

At the same time, the Promise instance can only have one state, and can only be changed once, after which it can no longer be changed.

There are only two ways to change: first, from pending to resolved; second, from pending to rejected.

The next step is to complete the use of a promise.

The first step is a new Promise instance. Code:


    var promise = new Promise(function(resolve,reject){
      if(/*Successful asynchronous execution*/){
        resolve(value)
      } else {
        reject(error)
      }
    });

Promise's constructor receives a function parameter and passes in two parameters, resolution. reject denotes the callback function after the asynchronous operation is successfully executed and the callback function after the asynchronous operation fails. Executing resolve() changes the status of the current promise object to resolve, and executing reject() changes the status of the current promise object to rejected.

At this point, a Promise object has been created, and the result of the asynchronous script has been stored in the Promise object, but is it a success or a failure? How do we read it?

The second step is the then method. Then the code is added:


    var promise = new Promise(function(resolve,reject){
      if(/*Successful asynchronous execution*/){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
    promise.then(function(value){
      console.log(value);
    },function(error){
      console.log(error);
    })

Each Promise instance has a then method that handles the asynchronous execution results stored in Promise. The then method can accept two callback functions as parameters. The first callback function is called when the state of the Promise object changes to Resolved, and the second callback function is called when the state of the Promise object changes to Reject. The second function is optional and does not have to be provided. Both functions accept the values passed out of the Promise object as parameters.

It should be noted that the return value of the then method is also a Promise! This means that the then method supports chain invocation.

The third step is the catch method.
The catch method is equivalent to then(null,function() {}), which is used to process Promise data in rejected state. As for catch, I think it's good to remember two things. First, use catch to process rejected Proise; second, use catch to capture Error objects thrown in all previous chain calls. Note that all errors thrown by these steps, including Promise constructors, the then method, the then method of chain calls, and previous catch, can be caught by catch.


    var promise = new Promise(function(resolve,reject){
      if(false){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
    promise
      .then(function(value){
        console.log(value);
      })
      .catch(function(reason){
        console.log(error);
      })

The above code outputs the error value passed in by reject(error), which is the first use of catch.


    var promise = new Promise(function(resolve,reject){
      if(true){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
    promise
      .then(function(value){
        console.log(value);
        console.log(x);
      })
      .catch(function(reason){
        console.log(reason);
      })

The code above changes Promise's state to resolved and executes the then method, which throws an undefined error in the x variable and captures and prints it by the catch method, which is the second use of catch.

So far we've actually learned the basics of Promise. Next, learn two more useful methods.

First, the Promise.all method.

This method can run the asynchronous method in parallel, process the results uniformly after they are returned, and return a new Promise object.


    var p = Promise.all([p1, p2, p3]);

In the code above, the Promise.all method accepts an "array" as a parameter, and p1, p2, and p3 are all instances of Promise objects.

The state of P is determined by p1, p2 and p3, which can be divided into two cases.

(1) Only when the states of p1, p2 and p3 are fulfilled can the states of P become fulfilled. At this time, the return values of p1, p2 and p3 form an array and are passed to the callback function of P. (fulfilled can be understood as resolved)

(2) As long as one of p1, p2 and p3 is rejected, the state of P becomes rejected, and the return value of the first rejected instance is passed to the callback function of P.


    var p = Promise.all([p1,p2,p3]);
    
    p.then(function(results){
        console.log(results)
    });

When opening a web page, we need to pre-load various resources such as images, flash and various static files. After all of them are loaded, we can initialize the page. This scenario is very suitable for Promise.all.

Second, the Promise.race method.

Similar to all methods, it is also possible to run asynchronous methods in parallel, and process the results uniformly after they are returned, and return a new Promise object.


    var p = Promise.race([p1,p2,p3]);

In the above code, as long as one instance of p1, p2, and p3 takes the lead in changing the state, the state of P changes accordingly. The return value of the Promise instance, which is the first to change, is passed to the callback function of p, that is, who executes it and who returns it quickly.

The race method can add restrictions on request timeouts.


    //Request an image resource
    
    function requestImg(){
        var p = new Promise(function(resolve, reject){
            var img = new Image();
            img.onload = function(){
                resolve(img);
            }
            img.src = 'xxxxxx';
        });
        return p;
    }
    
    //Delay function for timing requests
    
    function timeout(){
        var p = new Promise(function(resolve, reject){
            setTimeout(function(){
                reject('Picture request timeout');
            }, 5000);
        });
        return p;
    }
    
    Promise
    .race([requestImg(), timeout()])
    .then(function(results){
        console.log(results);
    })
    .catch(function(reason){
        console.log(reason);
    });

At this point, three questions about Promise have been answered, and I hope to provide some help for you to learn Promise.

Keywords: Javascript JSON

Added by taboo on Sun, 14 Jul 2019 23:34:38 +0300