What do you know about Promise?

First, the era before Promise — the callback era

Suppose we use getUser for user data, which receives two callbacks, sucessCallback and errorCallback:

function getUser(successCallback, errorCallback){
  $.ajax({
    url:'/user'.success: function(response){
      successCallback(response)
    },
    error: function(xhr){
      errorCallback(xhr)  
    }
  })
}
Copy the code

It doesn’t look too complicated.

If we get the user data and then get the grouping array, grouping details, etc., the code would look like this:

getUser(function(response){
    getGroup(response.id, function(group){
      getDetails(groupd.id, function(details){
        console.log(details)
      },function(){
        alert('Failed to get group details')})},function(){
      alert('Failed to get packet')})},function(){
  alert('Failed to obtain user information')})Copy the code

Three-level callbacks, with a little more nesting, are “callback hell.”

Two, Promise came

The idea behind Promise is that getUser returns an object to which you attach a callback:

var promise = getUser()
promise.then(successCallback, errorCallback)
Copy the code

When the user information is loaded, either successCallback or errorCallback is executed.

Put the above two sentences together and it looks like this:

getUser().then(successCallback, errorCallback)
Copy the code

If you want to do more after the user information is acquired, you can continue.

getUser().then(success1).then(success2).then(success3)
Copy the code

After the request is successful, Success1, Success2, and Success3 are executed.

To obtain grouping information:

getUser().then(function(response){
  getGroup(response.id).then(function(group){
    getDetails(group.id).then(function(){
      
    },error3)
  },error2)
}, error1)
Copy the code

This Promise writing doesn’t seem to change much from the previous callback.

True, Promise doesn’t eliminate callback hell, but it does make it manageable. You can see it by comparing the following two ways.

getGroup(response.id, success2, error2)

getGroup(response.id).then(success2, error2)
Copy the code

Until you use Promise, you can’t be sure what parameter Success2 is;

After I use Promise, all the callbacks are

.then(success, error) 
Copy the code

It looks like this.

The purpose of Promise

To recap: The Promise object is a JavaScript solution for asynchronous manipulation that provides a unified interface for asynchronous manipulation. It acts as a proxy, acting as an intermediary between asynchronous operations and callback functions, so that asynchronous operations have the interface of synchronous operations. Promise allows asynchronous operations to be written as if they were the flow of synchronous operations, rather than having to nest layers of callback functions.

How to create a New Promise

  • return new Promise((resolve,reject)=>{... })
  • Task call resolve(result)
  • Call Reject (error) when task fails
  • Resolve and reject call success and failure functions
  • Pass in the success and failure functions using.then(success,fail)

The following shows how to use:

var promise = new Promise(function (resolve, reject) {
  // ...

  if (/* Asynchronous operation succeeded */){
    resolve(value);
  } else { /* Asynchronous operation failed */
    reject(new Error()); }});Copy the code

In the code above, the Promise constructor takes a function as an argument, resolve and reject. They are two functions that are provided by the JavaScript engine and don’t have to be implemented themselves.

The resolve function is called when an asynchronous operation succeeds and passes the result of the operation as an argument.

The reject function is called when an asynchronous operation fails and passes any errors reported by the asynchronous operation as arguments.

5, How to use promise.prototype. Then (source MDN)

The then method of the Promise instance, used to add the callback function.

The then method can accept two callback functions, the first for the success of the asynchronous operation and the second for the failure of the asynchronous operation (this parameter can be omitted). Whenever the state changes, the corresponding callback function is called. The then method can be used chained.

p1
  .then(step1)
  .then(step2)
  .then(step3)
  .then(
    console.log,
    console.error
  );
Copy the code

In the code above, p1 is followed by four THEN, which means that there are four callback functions in sequence. As long as the state of the previous step becomes depressing, the callback functions that follow will be successively executed.

The last then method, the callbacks are console.log and console.error, with one important difference in usage. Console. log displays only the return value of step3, while console.error displays the error of any one of p1, step1, step2, or step3. For example, if the status of Step1 changes to Rejected, then step2 and Step3 won’t execute (because they are resolved callback functions). Promise starts looking, followed by the first callback function called Rejected, console.error in the code above. That is, the error of the Promise object is transitive.

How to use promise.all (source MDN)

The resolve method returns an instance of Promise that will call back to resolve when all promises within the iterable parameter are resolved; If the promise parameter has a failed (Rejected), this instance calls back failed (Reject), which is the result of the first failed promise.

Promise2.all = function(arrP) {
  let list = []
  let len = 0
  let hasErr = false
  return new Promise2((resolve, reject) = > {
    for(let i = 0; i < arrP.length; i++) {
      arrP[i].then( data= > {
        list[i] = data
        len++
        len === arrP.length && resolve(list)
      }, error= > {
        !hasErr && reject(error)
        hasErr = true})}})}Copy the code

How to use promise.race (source MDN)

Method returns an instance of a Promise that is resolved or reject once a Promise in the iterator is resolved or rejected

Promise2.race = function(arrP) {
  let hasValue = false
  let hasError = false
  return new Promise2((resolve, reject) = > {
    for(let i = 0; i < arrP.length; i++) {
      arrP[i].then(data= >{! hasValue && ! hasError && resolve(data) hasValue =true
      }, error= >{! hasValue && ! hasError &&reject(error) hasError =true})}})}Copy the code

Eight, summary

Promise has the advantage of making the callbacks formal and chained, so you can see the flow of the program. It has a whole set of interfaces that allow for many powerful functions, such as performing multiple asynchronous operations at the same time, waiting for their states to change, and then executing a callback function. For example, you can specify common handling methods for errors thrown in multiple callback functions.

What’s more, promises have another advantage that traditional writing doesn’t have: Once their state changes, they can get that state whenever they are queried. This means that whenever you add a callback function to a Promise instance, that function executes correctly. So you don’t have to worry about missing an event or signal. In the traditional way, the callback function is executed by listening for the event. If the event is missed, adding the callback function will not execute.

The downside of promises is that they are more difficult to write than traditional ones, and the code isn’t immediately readable. All you see is a bunch of THEN’s, and you have to sort out the logic in the then callback.