手写Promise源码

230 阅读8分钟

手写Promise源码

// promise有三种状态 pending 等待 fulfilled 成功 rejected 失败 // 且状态改变只能从pending -> fulfilled(从等待到成功) 或者 pending -> rejected(从等待到失败) 且状态改变后不可更改 // 声明三种状态常量 const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' // 创建Promise类 class MyProise { // Promise 对象需要传入一个执行器函数 该执行器函数会立即执行 并且该执行器函数有两个参数成功回调 失败回调 // 并且两个参数resolve和reject是来更改函数状态的 // resolve -> fulfilled(从等待到成功) // reject -> rejected(从等待到失败) constructor(executor) { // 使用trycatch是为了捕获执行器函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回 try { // 执行执行器函数 参数为更新函数状态的两个函数 executor(this.resolve, this.reject) } catch (error) { // 捕获执行器函数异常 将Promise类的函数状态更改为rejected this.reject(error) } } //记录函数状态并初始化函数状态为pending status = PENDING // 记录函数成功后的返回值 作为成功返回值给then方法成功回调 value = undefined // 记录函数失败后的返回值 作为失败原因给then方法失败回调 reason = undefined // 收集函数状态为成功的回调函数 successCallback = [] // 收集函数状态为失败的回调函数 failCallback = [] // 执行器成功函数 resolve = value => { // 函数状态更改后不可改变 若函数状态不为等待 拒绝向下执行 if (this.status !== PENDING) return // 将函数状态更改为成功 this.status = FULFILLED // 成功后的返回值 this.value = value // Promise函数具有thenable接口且可以多次调用 导致可能会有多个回调函数执行 // 使用while循环是因为数组变化导致循环体不成立时自动停止 while (this.successCallback.length) this.successCallback.shift()() } // 执行器失败函数 reject = reason => { // 函数状态更改后不可改变 若函数状态不为等待 拒绝向下执行 if (this.status !== PENDING) return // 将函数状态更改为失败 this.status = REJECTED // 失败后的返回值 this.reason = reason // Promise函数具有thenable接口且可以多次调用 导致可能会有多个回调函数执行 // 使用while循环是因为数组变化导致循环体不成立时自动停止 while (this.failCallback.length) this.failCallback.shift()() } // 类的thenable接口 then(successCallback, failCallback) { // then方法具有thenable接口 可以链式调用 需要返回一个promise对象 // 创建Promise对象 let promise = new MyPromise((resolve, reject) => { // then函数的状态取决于回调函数运行状态 现在判断状态 if (this.status === FULFILLED) { // 状态为成功

            // 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
            // 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
            setTimeout(() => {
                // 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
                try {
                    let result = successCallback(this.value)
                    // result的值可能存在两种情况普通值和promise对象
                    // 如果为普通值直接调用resolve返回
                    // 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
                    // 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
                    // 此逻辑我们用一个函数来实现 因此我们需要传入四个参数 
                    // 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
                    resolvePromise(promise, result, resolve, reject)
                } catch (error) {
                    // 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
                    reject(error)
                }
            }, 0)
        } else if (this.status === REJECTED) {
            // 状态为失败

            // 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
            // 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
            setTimeout(() => {
                // 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
                try {
                    let result = failCallback(this.value)
                    // result的值可能存在两种情况普通值和promise对象
                    // 如果为普通值直接调用resolve返回
                    // 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
                    // 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
                    // 此逻辑我们用一个函数来实现 因此我们需要传入四个参数 
                    // 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
                    resolvePromise(promise, result, resolve, reject)
                } catch (error) {
                    // 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
                    reject(error)
                }
            }, 0)
        } else {
            // 状态为等待
            // 此时需要等待then方法执行完毕才能直到函数状态 
            // 故将成功回调和失败回调存储起来 待状态更改之后在调用
            this.successCallback.push(() => {
                // 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
                // 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
                setTimeout(() => {
                    // 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
                    try {
                        let result = successCallback(this.value)
                        // result的值可能存在两种情况普通值和promise对象
                        // 如果为普通值直接调用resolve返回
                        // 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
                        // 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
                        // 此逻辑我们用一个函数来实现 因此我们需要传入四个参数 
                        // 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
                        resolvePromise(promise, result, resolve, reject)
                    } catch (error) {
                        // 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
                        reject(error)
                    }
                }, 0)
            })
            this.failCallback.push(() => {
                // 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
                // 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
                setTimeout(() => {
                    // 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
                    try {
                        let result = failCallback(this.value)
                        // result的值可能存在两种情况普通值和promise对象
                        // 如果为普通值直接调用resolve返回
                        // 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
                        // 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
                        // 此逻辑我们用一个函数来实现 因此我们需要传入四个参数 
                        // 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
                        resolvePromise(promise, result, resolve, reject)
                    } catch (error) {
                        // 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
                        reject(error)
                    }
                }, 0)
            })
        }
    })
    // 返回then函数的promise对象
    return promise
}
// 类的finally方法 参数为回调函数
// finally方法的内容都会被执行一次
// finally方法之后可以链式调用then方法
finally(callback) {
    // 在finally 内部可以通过then方法拿到 当前promise的状态 
    // 并且then方法返回promise对象 可以链式调用then方法
    return this.then(value => {
        // 如果finally的回调函数是promise 需等待回调函数执行完成在将结果返回给之后的链式调用
        return MyProise.resolve(callback()).then(() => value)
    }, reason => {
        // 如果finally的回调函数是promise 需等待回调函数执行完成在将结果返回给之后的链式调用
        return MyProise.resolve(callback()).then(() => {throw reason})
    })
}
// 捕获异常
catch(failCallback){
    // 使用then方法去注册失败回调 并置空成功回调
    return this.then(undefined, failCallback)
}
// promise.all()方法 参数为数组 返回结果为数组内的元素顺序(且为promise对象), 不论有无延迟
// 解决异步并发问题
static all(array){
    // 声明结果数组 作为all方法的返回值
    let result = []
    // all方法中有可能有promise的异步操作, 为保证参数数组中每一项都有返回值 需对返回结果修改时进行标记(累加处理)
    let index = 0
    return new MyProise((resolve, reject) => {
        // 将结果放入结果数组
        function addData(key, value){
            result[key] = value
            // 累加处理
            index++
            // 当所有结果都有返回值时 执行all方法的成功回调
            if(index === array.length){
                resolve(result)
            }
        }
        // 遍历当前数组 并且判断循环体是普通值还是promise对象
        for(let i = 0; i < array.length; i++){
            // 劫持循环体
            let current = array[i]
            if(current instanceof MyProise){
                // 循环体为promise对象 根据其运行结果调用resolve和reject更改状态
                current.then(value => addData(i, value), reason => reject(reason))
            }else {
                // 循环体为普通值
                addData(i, current)
            }
        }
    })
}
// Promise.resolve()方法返回一个promise对象
static resolve (value){
    // 如果value是promise对象直接返回
    if(value instanceof MyProise) return value 
    // 如果value是普通值 返回一个promise对象 并且将value当作成功返回值返回
    return new MyProise(resolve => resolve(value))
}

} function resolvePromise(promise, result, resolve, reject) { // 如果then方法返回值promise 和 then方法成功回调的返回值 相同 if (promise === result) { // 抛出错误 promise对象循环调用 return reject(new TypeError('TypeError: Chaining cycle detected for promise #')) } // 如果then方法成功回调的返回值 是promise对象 if (result instanceof MyProise) { // 调用promise对象的then方法 根据执行结果决定调用resolve还是reject result.then(resolve, reject) } else { // 如果then方法成功回调的返回值 是普通值 resolve(result) } }