preface

Recently, it took three hours to discover the error in the development process due to a misunderstanding of promise’s state dependence. I felt it was a waste of time, so I made a summary of the state dependence of promise based on the results of standard and practice.

The code in question looks something like this:

// Assume that promise is a request error callback
 let promise = new Promise((resolve, reject) = > {
    reject('400'); 
 });
 
 // Unified response interception handling
 promise.then((res) = > {
    console.log('promise injector resolved', res) 
 }, (err) => {
    console.log('promise injector rejected', err) 
 })
 // Request business response processing at invocation
 .then((res) = > {
    console.log('promise resolved', res) 
 }, (err) => {
    console.log('promise rejected', err) 
 })
 
Copy the code

The scenario shown in the code above is that after the error request is processed uniformly by the request response interceptor, the business logic itself does some additional processing based on the request state. Originally, according to my understanding of promise, there was no problem. In fact, the problem here is that the request response processing in the business will always only go through a success callback, not a failure callback. This is because the promise state is lost in the unified response interception process.

Three states of promise

Promise has three states:

  • Pending-promise Indicates the initialization state
  • Successfully Fulfilled –
  • Rejected – failure

These three states are Promises/A+ terms for states

When we create a promise, its state is Pending. Then, as the asynchronous task executes, its state must become one of the Fulfilled and Rejected, and its state will not change again (this is very important, Make clear the return value of promise.then().

Promise.then () returns a new promise

Let’s start with a code:

let promise = Promise.resolve('test');

let thenPromise = promise.then( res= >{
    console.log(res)
});
console.log(promise === thenPromise);
console.log(thenPromise);
Copy the code

The running results are as follows:

Two points can be easily drawn from the running results:

  1. Promise.then () returns a different promise than the promise that calls.then()
  2. The promise state returned by promise.then() is resolved, which corresponds to the promise state described in this article.

Promise.then () returns a new instance of a promise, and promises can represent states, thus forming a dependency chain of states. This allows you to represent the dependencies and order of execution between multiple tasks, transforming the nesting of callbacks for asynchronous tasks into a flat chain.

promise chain

A promise chain is basically a call chain of a promise, and the code form is roughly as follows:

var promise1 = Promise.reject('test');
promise1.then(function(res) {
    console.log('fulfilled1', res)
}, function(err) {
    console.log('rejected1', err)
    return err;
}).then(function(res) {
    console.log('fulfilled2', res)
}, function(err) {
    console.log('rejected2', err)
})
Copy the code

This chain-call approach is a good way to transform multiple asynchronous tasks with dependencies and ugly nested callbacks into a flat chain that is easier to understand. Thus solving the problem known as callback hell.

Both return values of the promise.then() callback function

Once we create a promise, we can use promise.then() to register the implementation function corresponding to the Fulfilled and Rejected states. Something like this:

var promise = new Promise((resolve, reject) = >{
    resolve('ok');
});
promise.then((res) = >{
    console.log('fulfilled', res)
}, (err)=>{
    console.log('rejected', err)
})
Copy the code

Promise.then () registers callback functions that can return different values, divided into the following:

  • Returns any value other than the Promise instance object
  • Promise instance object

Promise.then () the effect of the value returned by the callback function on the Promise chain

Promise.then () the return value of the callback determines the promise it returns, in two cases:

  1. The callback function returns any value other than the Promise instance object, determining the argument to the returned promise-registered callback function
  2. The callback function returns the Promise instance object, determining the state of the Promise returned by promise.then() and the arguments to its registered callback function

Note: The callback function here refers to the callback registered with promise.then(), and refers to the function being called, regardless of whether it is a successful or failed callback

The callback function that is executed returns any value other than the Promise instance object

When a callback registered with promise.then() returns a value other than a promise, the returned value is treated as the incoming value of the callback registered with.then() for the new promise returned by promise.then().

When the callback function does not return a value, consider the following code:

let promise = Promise.resolve();
promise.then((a)= >{
    console.log('promise resolved')}, () = > {console.log('promise rejected')
})
.then((value) = >{
    console.log('promise resolved1')
    console.log(value)
}, (err)=>{
    console.log('promise rejected1')
    console.log(err)
})

// promise resolved
// promise resolved1
// undefined

let promise1 = Promise.reject();
promise1.then((a)= >{
    console.log('promise1 resolved')}, () = > {console.log('promise1 rejected')
})
.then((value) = >{
    console.log('promise1 resolved1')
    console.log(value)
}, (err)=>{
    console.log('promise1 rejected1')
    console.log(err)
})

// promise1 rejected
// promise1 resolved1
// undefined
Copy the code

The promise registered callback ran a success callback, and then returned a promise in a success state. The returned promise registered callback ran a success callback, and the argument to the callback was undefined. The promise1 registered callback runs a failure callback and returns a promise of success status. The promise1 registered callback runs a success callback and its argument is undefined

Js functions return undefined by default

Let’s look at the other values:

let promise = Promise.resolve();
promise.then((a)= >{
    console.log('promise resolved')
    return 'value'= > {}, ()console.log('promise rejected')
    return 'err'
})
.then((value) = >{
    console.log('promise resolved1')
    console.log(value)
}, (err)=>{
    console.log('promise rejected1')
    console.log(err)
})
// promise resolved
// promise resolved1
// value

let promise1 = Promise.reject();
promise1.then((a)= >{
    console.log('promise1 resolved')
    return 'value'= > {}, ()console.log('promise1 rejected')
    return 'err'
})
.then((value) = >{
    console.log('promise1 resolved1')
    console.log(value)
}, (err)=>{
    console.log('promise1 rejected1')
    console.log(err)
})
// promise1 rejected
// promise1 resolved1
// err
Copy the code

Promise.then () registers a callback that runs a success callback and returns the string “value.” Promise.then () returns a promise with a success status. The argument to the callback function is the string “value”; Promise1.then () returns a promise of success status. Promise1.then () returns a promise of success status. The argument to the callback function is the string “err”

From the above two sample codes and their running results, it is not difficult to draw the following conclusions:

  1. When promise.then() registers a callback that does not return a promise sample object (the code only returns string and undefined, but other types can be verified by interested students), Promise.then () returns a new promise instance that is a Fulfilled state
  2. The argument to this successful callback is the return value of the last callback function that was run

The executed callback returns the Promise instance object

When the promise.then() registered callback returns a promise instance, the final state of the returned promise instance determines the state of the new promise returned by promise.then(). And the promise.then() function returns a promise-registered callback whose arguments are determined by the arguments passed by the Promise instance object resolve or Reject.

Consider the following code:

let promiseValue = Promise.reject('promiseValue err');

let promise = Promise.resolve();
let promiseThen = promise.then((a)= >{
    console.log('promise resolved');
    return promiseValue;
})
promiseThen.then((res) = >{
    console.log('promise resolved1');
    console.log(res)
}, (err)=>{
    console.log('promise rejected1');
    console.log(err);
})

// promise resolved
// promise rejected1
// promiseValue err

console.log(promiseThen === promiseValue)

// false
Copy the code

The promise performs a success-state callback, which returns the promiseValue instance object in the failed state, and its rejecte is passed in as the string “promiseValue Err”. Promise.then () returns a new promise instance (promiseThen === promiseValue) because the state of promiseevalue is Rejected Promise.then () returns the state of promiseThen (rejected), the failed callback to promiseThen registration is called, and the printed argument is the string “promiseValue err”.

Promise.then () registers when the executed callback returns a Promise instance object:

  1. Promise.then () returns a new Promise instance object. This instance object will wait for the callback function to return the promise instance object state which becomes one of the Fulfilled or Rejected states. And the state is the same as the state of the Promise instance object returned by the callback function
  2. Promise.then () returns the promise instance object. The arguments that the registered callback takes when executed are determined by the result that the callback returns from the Promise instance object

conclusion

That’s because promise.then() returns a new promise instance, and that instance can pass back the execution status and data of the previous promise-dependent asynchronous task. This chaining mechanism solves the problem that dependent asynchronous tasks can only be nested in the callback function, resulting in difficult code maintenance.