Chain calls

The.then method of a Promise returns a new Promise (same as catch), so you can link the then.

Both its value and state depend on the execution of the previous THEN

1, the previous then does not return a value

The new promise instance is fulfilled and its value is undefined

let p1 = new Promise((resolve,reject) = > {
    resolve(1);
})

let p2 = p1.then((value) = > {
    console.log('xxx');
})
// This is a big pity. P2 :{< depressing >: undefined}
Copy the code

2. The previous THEN returns any value that is not a promise

The state of the new Promise instance is FULFILLED and the value is the return value

let p1 = new Promise((resolve,reject) = > {
    resolve(2);
})

let p2 = p1.then((value) = > {
    return 6;
})
// This is a big pity. P2 :{< depressing >: 6}
Copy the code

3explicitReturns a promise

The result of the new Promise instance is equal to the result of the returned promise

let p1 = new Promise((resolve,reject) = > {
    resolve(3);
})

let p2 = p1.then((value) = > {
    return Promise.resolve(9);
})
// This is a big pity. P2 :{< depressing >: 9}
Copy the code

4, Then does not provide onResolved or onRejected methods

If the last Promise instance was successful and the THEN does not provide the onResolved method, it is based on the result of the last Resolve

let p1 = new Promise((resolve,reject) = > {
    resolve(2);
})

let p2 = p1.then();
// This is a big pity. P2 :{< depressing >: 2}
Copy the code

5. An error was thrown in the previous then

The new Promise instance is in the state rejected and the value is the exception thrown

let p1 = new Promise((resolve,reject) = > {
    resolve(2)})let p2 = p1.then((value) = > {
	throw new Error('fail');
})
// p2:{
      
       : 'fail'}
      
Copy the code

Interrupt the chain of promise

If, after a certain step, you do not want to execute subsequent THEN and thus interrupt the promise chain, you can return a promise in a pending state:

new Promise((resolve, reject) = > {
    resolve(100)
}).then(value= > {
    
}).then(value= > {
    // Stop at this point
    return new Promise(() = > {})
}).then(value= > {
    
}).catch(reason= > {
    console.log(reason)
})
Copy the code

Writing this way, neither the last THEN nor the last catch will be implemented (because there is no way to receive a promise instance of pity or Rejected).

Error handling

As mentioned earlier, the error handler in the Promise, the rejection handler, is either passed to the second argument to the then function, or caught with a catch. If the callback from THEN fails, then returns a Promise in the Rejected state, like this:

var p = Promise.resolve(42);

p.then((msg) = > {
    console.log(msg.toLowerCase());
}, (err) = > {
    console.log(err); // Never execute
})
Copy the code

The state of P is fulfilled, and the return value is 42. But in the success handler function, the number type has no toLowerCase method, so an error will be thrown.

But why isn’t this error caught by our error handler?

Because the p promise is already filled with 42 and is in fulfiiled state, it will not be changed. So p.t hen (…). Errors are notified to p.teng (…) .then(…) But we didn’t capture it here.

To avoid losing promises that are ignored or discarded, some developers say it’s best practice to always end with a catch(..). End. This treatment is called abnormal penetration.

If the first promise fails, then does not write the onRejected function:

new Promise((resolve, reject) = > {
    reject(1);
}).then(value= > {
    
}).then(value= > {
    
}).then(value= > {
    
}).catch(reason= > {
    console.log(reason);
})
Copy the code

The reject(1) passes through the final catch layer by layer (note: it doesn’t find the last catch all at once)

Execution of either then or catch depends on the previous THEN ()

Since then does not manually write the onRejected function, it defaults to this:

.then(value= >{},reason= > {
	throw reason;
})
Copy the code

But either way, at the last step in the Promise chain, there’s always the possibility of an uncaught error, though it’s getting less and less likely.

Is there a way around this?

Some Promise libraries add methods to register a “global unhandled rejection” handler so that it doesn’t throw a global error, but instead calls the function.

window.addEventListener("unhandledrejection", handler);
Copy the code

One idea is that promises should add a done function, essentially marking the end of the Promise chain. An error thrown in a done callback is treated as a global unhandled error and can be found in a try… Caught in the catch block.

However, it is not part of the ES6 standard and we can choose to implement it ourselves:

Promise.prototype.done = function (onFulfilled, onRejected) {
    this
        .then(onFulfilled, onRejected)
        .catch(function (reason) {
        // Throws a global error
        setTimeout(() = > {
            throw reason
        }, 0); })}Copy the code