Promise使用及源码了解

41 阅读6分钟

当我们需要给予调用者一个承诺:待会儿我会给你回调数据时,就可以创建一个Promise的对象;

在通过new创建Promise对象时 ,我们需要传入一个回调函数,我们称之为executor,这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject;

  • 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;
  • 当我们调用reject回调函数时 ,会执行Promise对象的catch方法传入的回调函数;

基本用法:

Promise 内传入的这个函数被称为executor, resolve : 回调函数,在成功时回调resolve函数 reject : 回调函数,在成功时回调 reject 函数

const promise = new Promise((resolve, reject) => {
    // 执行传入的回调函数
    resolve()
    // reject()
})

promise.then(() => {})
promise.catch(() => {})

等价于:

new Promise((resolve, reject) => {
    // 执行传入的回调函数
    resolve()
    // reject()
}).then(res => {
    console.log(res);
}).catch(err => { 
    console.log(err);
})

状态值

pending(待定)

初始状态,当执行executor中的代码,处于该状态

fulfilled(成功)

操作成功,执行resolve函数处于该状态

rejected(失败)

操作失败,执行reject函数处于该状态

状态值不可逆,只能由 pending -> fulfilled/resolved pending-> rejected

fulfilled 和resolved 是同一个东西

resolve(参数)

参数值:

  1. 普通对象或者数据 resolv会将状态由 pending -> fulfilled 2.传入 Promise 对象 如果给resolve传入一个Promise对象,那么这个状态会由传入的Promise决定, 相当于状态移交 3.传入一个对象,且对象有实现then方法(该对象实现了thenable) 那么也会执行then方法,并且该then方法的结果决定后续状态

resolve传值三种情况:

// 不使用的时候先注掉
// const p1 = new Promise((resolve, reject) => {
//     reject("传入Promise对象")
// })

const obj = {
    then: function (resolve, reject) {
        resolve("传入thenable对象")
    }
}

new Promise((resolve, reject) => {
    // 执行传入的回调函数

    // 情况一:传入普通值 字符串
    // resolve("123")

    // 情况二:resolve传入一个Promise
    // resolve(p1)

    // 情况三:传入thenable对象
    resolve(obj)

}).then(res => {
    console.log("成功回调", res);
}).catch(err => {
    console.log("失败回调", err);
})

在些在后续实现Promise 时都要考虑

resolve返回值是一个Promise

executor

在创建Promise 传入的一个回调函数,回调函数会被立即执行,并传入两个参数:

new Promise((resolve, reject) => {
    resolve("executor代码")
})

then

the方法是放在Promise原型上的Promise.prototype.then() 接收两个参数:

  • fulfilled的回调函数:成功回调
  • rejected 的回调函数:失败回调

then方法可以被回调多次,且在成功状态下时,会全部回调

then返回值是一个Promise,如果返回的是一个普通值,这个普通值会作为一个新的Promise传递

new Promise((resolve, reject) => {
    resolve("123")
}).then(res => {
    console.log("成功回调", res);
}, err => {
    console.log("err", err);
})

finally

finally没有参数,无论成功还是失败,最后都会走到 finally

new Promise((resolve, reject) => {
    resolve("123")
}).then(res => {
    console.log("成功回调", res);
}, err => {
    console.log("err", err);
}).then(res => {
    console.log("455454");
}).finally(() => {
    console.log("finally");
})

Promise.resolve()

类方法 resolve 内的参数和executor内的参数状态一致

const promise = Promise.resolve({ name: '123' })
// 等价于
const promise1 = new Promise((resolve, reject) => {
    resolve({ name: "123" })
})

将内部参数转成prmise返回回去

Promise.reject()

const promise = Promise.reject("rejected msg")
// 等价于
const promise1 = new Promise((resolve, reject) => {
    reject("rejected msg")
})

内部操作

// reject内部不管传什么值,直接走catch
const promise = Promise.reject(new Promise(() => { }))
promise.then(res => {
    console.log("res", res);
}).catch(err => {
    console.log("err", err); // err Promise { <pending> }
})

Promise.all()

在内部所有的Promise都变成fulfilled时,再拿到结果 但是在拿到结果之前,有一个结果变成rejected,那整个promise都会变成rejected

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("p1-reolve-2s")
    }, 2000)
})
const p2 = new Promise((resolve, reject) => {
    resolve("p2--resolve")
    // reject("p2-reject")
})

Promise.all(['a', 'b', p1, p2, 'c']).then(res => console.log("res-all", res))
// res-all [ 'a', 'b', 'p1-reolve-2s', 'p2--resolve', 'c' ]

Promise.allSettled()

all的缺点是:当状态有一个是rejected,那promise整体都会变成rejected 等于,获取不到内部其他结果。 ES11(ES2020) 中添加了allSettled,这个方法会在所有Promise都有结果(settled),无论状态是pending还是rejected,都会有结果;而且这个Promise结果一定是fulfilled的

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("p1-reolve-2s")
    }, 2000)
})
const p2 = new Promise((resolve, reject) => {
    reject("p2-reject")
})


Promise.allSettled(['a', 'b', p1, p2, 'c']).then(res => console.log(res))

/*
[
  { status: 'fulfilled', value: 'a' },
  { status: 'fulfilled', value: 'b' },
  { status: 'fulfilled', value: 'p1-reolve-2s' },
  { status: 'rejected', reason: 'p2-reject' },
  { status: 'fulfilled', value: 'c' }
]
*/

可以看到打印结果: 成功的状态为fulfilled,返回value为 传入的值 失败的状态为rejected,返回 reason 为 传入的值

allSettled的结果是一个数组,数组内存放着每一个Promise结果,并对应每一个对象,对象内部包含 当前 status状态值、value 运行返回结果(成功是value),reason(失败原因)

Promise.race()

只要有一个fulfilled,直接返回正常,或者是有一个异常 直接 reject

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("p1-reolve-2s")
    }, 2000)
})
const p2 = new Promise((resolve, reject) => {
    reject("p2-reject")
})

Promise.race([p1, p2]).then(res => {
    console.log("res", res) 
}).catch(err => {
    console.log("err", err);  // err p2-reject
})

Promise.any()

any() 至少要等到一个resolve结果 返回 如果没有resolve,才会执行catch 会给一个合计结果

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("p1-reolve-2s")
    }, 2000)
})
const p2 = new Promise((resolve, reject) => {
    reject("p2-reject")
})

Promise.any([p1, p2]).then(res => {
    console.log("res", res) // res p1-reolve-2s
}).catch(err => {
    console.log("err", err);  

Promise源码

const PENDING = "PENGING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";


class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (err) {
            this.reject(err)
        }
    }
    // 设置promise初始状态
    status = PENDING;
    // 成功后的值
    value = undefined
    // 失败后的值
    reason = undefined
    // 成功回调
    successCallback = []
    // 失败回调
    failCallback = []

    resolve = value => {
        // 如果状态不是等待,阻止程序向下执行
        if (this.status !== PENDING) return;
        // 将状态改为成功
        this.status = FULFILLED
        // 保存成功后的原因
        this.value = value
        // 判断成功回调是否存在,如果存在,调用
        // this.successCallback && this.successCallback(this.value)
        while (this.successCallback.length) this.successCallback.shift()()

    }
    reject = reason => {
        // 如果状态不是等待,阻止程序向下执行
        if (this.status !== PENDING) return;
        // 将状态改为失败
        this.status = REJECTED
        // 保存失败后的原因
        this.reason = reason
        // 判断失败回调是否存在,如果存在,调用
        // this.failCallback && this.failCallback(this.reason)
        // 处理promise多个then方法调用情况
        while (this.failCallback.length) this.failCallback.shift()()

    }
    then(successCallback, failCallback) {
        successCallback = successCallback || (value => value);
        failCallback = failCallback || (reason => { throw reason });
        // then的链式调用,需要返回一个promise对象
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value)
                        // 将上一个then的返回值,传递给下一个then
                        // resolve(x)

                        // 这里返回的值会有多种:普通值、promise对象、实现thenable的对象
                        // 1.如果是普通值,直接调用resolve 
                        // 2.如果是promise对象,查看promise对象返回的结果
                        // 再根据promise返回的结果决定调用resolve 还是reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                }, 0)

            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                }, 0)
            } else {
                // promise是立即执行,当在请求接口或者延迟执行时会进入等待状态
                // 所以不确认是成功还是失败

                // 等待 将成功回调或失败回调存储起来


                this.successCallback.push(() => {
                    // successCallback()
                    setTimeout(() => {
                        try {
                            let x = successCallback && successCallback(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    // failCallback()
                    setTimeout(() => {
                        try {
                            let x = failCallback && failCallback(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }
                    }, 0)
                })
            }
        });
        return promise2
    }

    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }

    catch(failCallback) {
        return this.then(undefined, failCallback)
    }

    static all(array) {
        let result = []
        let index = 0

        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value
                index++
                // 等所有异步操作完成后,才可以调用resolve方法
                if (index === array.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i])
                }
            }
        })
    }

    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }
}



function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    // 判断x是否为promise实例
    if (x instanceof MyPromise) {
        // promise对象
        // x.then(value => resolve(value), reason => reject(reason))
        // 可以简化为下方代码
        x.then(resolve, reject)
    } else {
        // 普通值
        resolve(x)
    }
}
module.exports = MyPromise