Keep a record of the learning experiences you promise

Meet the Promise in ES6

The Promise object is essentially designed to help solve a serious flaw in asynchronous code implementations that can only be implemented through callbacks, colloquically the extra cost of code understanding and bug checking that comes with callback hell, and the convenience of link calls and bug tracking, combined with generators, Is a big step in javascript asynchronous flow control.

The internal properties of a Promise

state

Pending: pending state, promise initial state; Fulfilled: has been completed, the rejected success: has refused, failure (state only by pending – > fulfilled | | pending – > the rejected, and once the state change, can’t change)

Promise value

The value corresponding to the value property inside the Promise object; Each state change synchronously changes the value property inside the Promise, which defaults to undefined.

The basic structure and use of Promise

New Promise(Handler (resolve, reject) => {}) Parameter Handler must be a function that contains arguments of both function types

new Promise((resovle, reject) = > {
    resolve(1); // Promise internal value is changed to 1
    // reject('rejected~') // Promise internal value to string 'rejected~'
}).then(
    resolveResult= > {
        // This corresponds to the resolve successful callback, taking the value of the previous PROMISE and printing 1
        console.log(resolveResult) 
    },
    rejectResult= > {
        // The reject callback is rejected, taking the previous promise value and printing rejected~
        console.log(rejectResult)
    }
)
Copy the code

Promise’s common API

then

Promise implements internal linking via.then. Calls to this method take up to two arguments, corresponding to the success and failure callbacks of the previous promise (the second argument is omitted), and return a new Promise object. If the previous.then function returned a promise internally, The current.THEN is executed after the returned Promise’s state has changed from pending, taking the value of that Promise. The.then argument displays a return value, which is the value of the current Promise and is treated as an argument to the next.then. If no return is displayed, the function executes with undefined and passes undefined as an argument inside the next.then function

        new Promise((resolve, reject) = > {
            setTimeout(() = > {
                resolve(1)},2000)
        }).then(res= > {
            console.log(1); // Print 1 after 2 seconds}) If resolve is a promise, then the result of the internal promise is taken as an argument to the next.then internal callbacknew Promise(async (resolve, reject) => {
            resolve(new Promise((resolve) = > {
                setTimeout(() = > {
                    resolve(3)},2000)
            }))
        }).then(res= > {
            console.log(res); // Print 3 after 2 seconds}).then, which receives the previous onePromiseFailure callback fornew Promise(async (resolve, reject) => {
            reject(404)
        }).then(res= > {
                console.log(res); // It won't come in here
            },
            err= > {
                console.log(err, 'the rejected callback'); // Print 404, rejected callback}).then a new promise is returned inside and passedreturnChanged the currentPromiseSo you can continue the link call.then with the current argumentPromiseThe value of the; If there is an error in the current.THEN code, the error will be caught by the second argument to the.THEN, the corresponding failure callbacknew Promise((resolve, reject) = > {
    reject(404)
})
    .then(
        (res) = > {
            console.log(res)
        },
        (err) = > {
            console.log(err, 'the rejected callback');
            // The variable b is not defined, so an error is reported,
            // This error is received by the second failure callback to.then, taking the error object
            // console.log(b);
            return 5; // If there is no return, then the next.then argument will be undefined
        }
    )
    .then(
        (res) = > {
            console.log('.then1', res) // Will print here, '.then1, 5'
        },
        (err) = > {
            console.log(err, '.then1--err')}) if the previous.thenreturnThe current.then receives the value of the promise's state changenew Promise((resolve, reject) = > {
    reject(404)
})
    .then(
        (res) = > {
            console.log(res)
        },
        (err) = > {
            console.log(err, 'the rejected callback');
            return new Promise((resolve) = > {
                setTimeout(() = > {
                    resolve(777)},1000);
            })
        }
    )
    .then(
        (res) = > {
            console.log('.then1', res); // Print '.then1, 777' here after 1 second})Copy the code

resolve

Promise Calling resolve directly returns a Promise object

Promise.resolve(6).then(res= > {
    console.log(res); // Print 6 here
})
Copy the code

reject

Promise.reject(7).then(res= > {
    console.log(res)
}, err= > {
    console.log(err); // Print 7 here
})
Copy the code

all

This property takes an input of type iterable (Array, Map, Set), which is called an Array. There is no restriction on the types inside arrays. Return a Promise object whose resolve callback is the result of each execution of the array; If one of the items in the array fails, then the Promize callback will be executed directly, so the scenario needs to be evaluated to determine whether the. All method is needed, otherwise any of the items in the array will not be executed properly.

const p1 = Promise.resolve(0)
const p2 = 1
const p3 = new Promise((resolve) = > {
    setTimeout(() = > {
        resolve(2)},2000)})Promise.all([p1, p2, p3]).then(
    (res) = > {
        console.log(res); // Print after 2 seconds [0, 1, 2]
    },
    (err) = > {
        console.log(err); // If a promise or code execution error occurs inside P1, P2, or P3, enter here})Copy the code

race

Race, as the name implies, is a race. This method takes an iterator argument with.all. Once the state of one of the inner promises changes, the promise returned by race executes a callback to synchronize that state.

const p1 = new Promise((resolve) = > {
    setTimeout(() = > {
        resolve(2)},2000)})const p2 = new Promise((resolve) = > {
    setTimeout(() = > {
        resolve(3)},1000)})/** if list is changed to [p1, p2, 3], print 3*/
Promise.race([p1, p2]).then(
    (res) = > {
        console.log(res); // Print 3 here after 1 second
    },
    (err) = > {
        console.log(err)
    }
)
Copy the code

catch

The.catch method catches errors reported by Promise’s internal execution code and errors that are not caught by the.then error callback.

new Promise((resolve, reject) = > {
    console.log(b)
}).catch(err= > {
    console.log(err); // ReferenceError: b is not defined
})
Copy the code

If.then has a registered second function that receives rejected, then the error will be received by the secondary function and cannot be caught by catch

new Promise((resolve, reject) = > {
    console.log(b)
})
    .then(
        (res) = > {
            console.log(res)
        },
        (err) = > {
            console.log(err, 'reject capture') // The error message is caught here
        }
    )
    .catch((err) = > {
        console.log(err, 'catch caught'); // Failed to catch the previous error
    })
Copy the code

finally

The.finally method accepts a function that executes the previous promise whether it is in the resolve or rejected state and passes the value of the previous promise forward. The finally function does not change the value of the promise on the current call chain

Promise.resolve(8).finally(() = > {
    console.log('Execute the finally callback')
    return 9  // The return operation does not affect the values inside the PROMISE
}).then(res= > {
    console.log(res); // Print 8 here
})
Copy the code

Reference – The specific use and properties of a PROMISE

The handwritten Promise code is implemented as follows:

/**resolve, reject (); reject (); /**resolve, reject (); Value within the promise * status: the state of the promise, pending | fulfilled | any offers then rejected * (...). The object (or function) of the function is considered thenable */
class MyPromise {
    constructor(handle) {
        if (typeofhandle ! = ='function') {
            throw Error(The argument must be a function.)}this._value = undefined
        this.status = 'pending'
        FulFillCallbackList: Execution queue of fulfillcallbacks */
        this.fulFillCallbackList = []
        /**rejectCallbackList: execution queue for failed callbacks */
        this.rejectCallbackList = []
        /** Execute the incoming parameter function and change the point to this with bind. Calls to resolve and reject change the value inside the promise and synchronize the corresponding state */
        try {
            handle(this.resolve.bind(this), this.reject.bind(this))}catch (err) {
            this.reject(err)
        }
    }
    resolve(val) {
        /** Judge the state first */
        if (this.status ! = ='pending') return
        this.status = 'fulfilled'
        /** Successful cache queue */
        const runFulFilled = (thenValue) = > {
            let cb
            while ((cb = this.fulFillCallbackList.shift())) {
                cb(thenValue)
            }
        }
        /** Failed to execute cache queue */
        const runRejected = (thenRejectValue) = > {
            let cb
            while ((cb = this.rejectCallbackList.shift())) {
                cb(thenRejectValue)
            }
        }
        /** If val is a promise, the result of execution depends on the value of the previous promise */
        if (val instanceof MyPromise) {
            val.then(
                (result) = > {
                    this._value = result
                    runFulFilled(result)
                },
                (err) = > {
                    this._value = err
                    runRejected(err)
                }
            )
        } else {
            this._value = val
            runFulFilled(val)
        }
    }
    reject(err) {
        if (this.status ! = ='pending') return
        this.status = 'rejected'
        this._value = err
        let cb
        while ((cb = this.rejectCallbackList.shift())) {
            cb(val)
        }
    }
    /**fulfilled => The parameter is the value of the last promise fulfilled, and the parameter is the value of the last promise reject */
    then(thenFulFilled, thenRejected) {
        /** Get the state and value of the previous promise */
        const { status, _value } = this
        return new MyPromise((resolveNext, rejectNext) = > {
            /** Fufilled handler */
            const handleFulfilled = (val) = > {
                This will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled, this will be fulFilled This function will return undefined * if this function returns a promise, * < the instanceof operator is used to check whether the constructor's prototype property is present on the prototype chain of an instance object. > * If this is not a promise, Then treat this value as the new promise. * handleRejectd handles the same pattern */
                try {
                    if (typeofthenFulFilled ! = ='function') {
                        resolveNext(val)
                    }
                    const handleResult = thenFulFilled(val)
                    if (handleResult instanceof MyPromise) {
                        handleResult.then(resolveNext, rejectNext)
                    } else {
                        resolveNext(handleResult)
                    }
                } catch (err) {
                    rejectNext(err)
                }
            }
            /**rejectd handler */
            const handleRejectd = (val) = > {
                try {
                    if (typeofthenRejected ! = ='function') {
                        rejectNext(val)
                    }
                    const handleResult = thenRejected(val)
                    if (handleResult instanceof MyPromise) {
                        /** After the internal state of the new promise changes, a callback is made to change the value of the promise */
                        handleResult.then(resolveNext, rejectNext)
                    } else {
                        resolveNext(handleResult)
                    }
                } catch (err) {
                    rejectNext(err)
                }
            }
            /** Perform different operations based on the previous promise state */
            switch (status) {
                This is fulfilled. // If the state is fulfilled, it will be fulfilled directly
                case 'fulfilled':
                    handleFulfilled(_value)
                    break
                // If the state is rejectd, handle it directly
                case 'rejected':
                    handleRejectd(_value)
                    break
                // If the previous promise is still pending, register the callback function with
                case 'pending':
                    this.fulFillCallbackList.push(handleFulfilled)
                    this.rejectCallbackList.push(handleRejectd)
                    break}})}/**catch => We also need to return a MyPromise object and register an error exception callback function in the argument */
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    /**resolve static property */
    static resolve(val) {
        /** Return the parameter if it is of type PROMISE
        if (val instanceof MyPromise) {
            return val
        }
        return new MyPromise((resolve) = > {
            resolve(val)
        })
    }
    /**resolve static property */
    static reject(val) {
        return new MyPromise((resolve, reject) = > {
            reject(val)
        })
    }
    /**all static properties */
    static all(list) {
        return new MyPromise((resolve, reject) = > {
            let resultList = []
            list.forEach((item) = > {
                item.then(
                    (res) = > {
                        resultList.push(res)
                        if (resultList.length === list.length) {
                            resolve(resultList)
                        }
                    },
                    /**reject (reject) */
                    (err) = > {
                        reject(err)
                    }
                )
            })
        })
    }
    /** A static property of the race. The for loop implementation should be better and return */ in time
    static race(list) {
        return new MyPromise((resolve, reject) = > {
            list.forEach((item) = > {
                // As soon as one instance changes state first, the state of the new MyPromise will change accordingly
                item.then(
                    (res) = > {
                        resolve(res)
                    },
                    (err) = > {
                        reject(err)
                    }
                )
            })
        })
    }
    / * * reference within the promise for the description of the finally * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/ Global_Objects/Promise/finally * There is no need to declare the function multiple times or create a variable to hold it * There is no way to know the final state of the Promise, so the finally callback does not take any arguments. It is only used if it is executed regardless of the final result * by printing the result native to the promise. Finally should be a native promise. Finally is designed to indicate the final * logical processing of the previous promise state. So for subsequent.then operations, the finally argument received is undefined, which is the * one termination */ of the link call to the promise before the finally
    finally(cb) {
        /** return this.then to ensure that the call can continue after finally
        return this.then(
            (res) = > {
                console.log(res, 'zheli ')
                }}}}}}}}}}}}}}}}} Return mypromise.resolve (cb()).then(() => res) ()=> {return res}, callback res to the next. Then */
                return MyPromise.resolve(cb()).then(() = > res)
                // cb()
            },
            (err) = > {
                console.log(err, 'err')
                // MyPromise.resolve(cb()).then(() => {
                // throw err
                // })
                return MyPromise.resolve(cb()).then(() = > err)
                // cb()})}} Code performs process validationconsole.log('mypromise------start')
MyPromise.reject(1)
    .then(
        (res) = > {
            console.log(res, '1111111, this is 1. ')
            return 3
        },
        (err) = > {
            console.log(err, 'index')
        }
    )
    .then((res) = > {
        // console.log(BBB) // let the function go to rejected
        return new MyPromise((resolve) = > {
            setTimeout(() = > {                
                resolve('6666')},2000);
        })
    })
    .finally(() = > {
        console.log('finally')
    })
    .then(
        (res) = > {
            console.log(res, 'mypromise--2222'); // After 2 seconds print '6666, myPromise --2222'
        },
        (err) = > {
            console.log(err, 'mypromise---222--reject')})Copy the code