promise详解 : 实现promise(附实现代码)

promise then 的特点 :

  • then 函数的返回值是一个 promise, 可以继续调用 then 函数
  • 回调函数 resolve 和 reject 的参数 value /reason, 可以传递给 then函数的回调函数, 最终 resolve(res) 的res 传递给了 then(onFulfilled(v)=>{},onrejected(e)=>{}) 中的 v, 而 reject(err) 中的 err 传递给了其中的 e

then 函数的回调函数的返回值可以分成 :

  • 普通值(字符串、对象、函数、undefined等), 只要不是 promise 或者 错误, 都可以看做是普通值
  • Promise 的实例
  • 错误

根据 then 函数的回调函数的返回值, 确定下一次链式调用的方式

  • then 函数的回调函数的返回值 : 即 onFulfilled 函数的返回值 , 或者 onRejected 的函数的返回值

1. then 函数的回调函数的返回值是普通值

  • then 函数的返回值可以是 onFulFilled 函数的返回值, 也可以是 onRejected 函数的返回值, 若是不用 return 指定返回值, 则默认返回undefined。 如果该返回值是普通的值, 则下一次链式调用(即调用then)进入 onFulfilled 回调函数, 并且将该返回值作为 onFulfilled 回调函数的参数
const p = new Promise((resolve, reject)=> {
    setTimeout(()=> {
        resolve('ok1')
    },1000)
})
p.then(res=> {
    return 'ok2'
}).then(res=> {
    console.log(res)
}).then(res=> {
    console.log(res)
})
// 输出:
// ok2
// undefined
  • 对于 onReject 返回普通类型的值, 也按照上述规则:
const p = new Promise((resolve, reject)=> {
    setTimeout(()=> {
        reject('not ok1')  
    },1000)
})
p.then(res=> {
    return 'ok2'
},(e)=> {
    return 'not ok2'
}).then(res=> {
    console.log(res)
},(e)=> {
    console.log(e)
}).then(res=> {
    console.log(res)
})
// 输出 :
// not ok2
// undefined
  • 在 onRejected 回调函数中不用return指定返回值, 在下一次链式调用的时候, 也会 进入 resolve 函数, 只有发成错误才可以进入下个链式调用的 Onrejected 回调函数:
const p = new Promise((resolve, reject)=> {
    setTimeout(()=> {
        reject('not ok1')  
    },1000)
})
p.then(res=> {
    return 'ok2'
},(e)=> {
    console.log(e)
}).then(res=> {
    console.log(res)
},(e)=> {
    console.log(e)
}).then(res=> {
    throw new Error('Error')
}, e=> {
    console.log(e)
}).then(res=> {
    console.log(res)
},e=> {
    console.log(e)
})
// not ok1
// undefined
// Error: Error

2. then 函数的回调函数的返回值是 Promise 的实例, 即一个新的 promise

  • 下一次链式调用会采用这个被返回的 promise 的状态, 如果这个 promise 的状态是 fulfilled 的则, 下次链式调用进入 onFulfilled 函数, 如果这个promise 的状态是 rejected, 则下次链式调用进入 onRejected 函数
const p = new Promise((resolve, reject)=> {
    setTimeout(()=> {
        resolve('ok1')  
    },1000)
})
p.then(res=> {
    return new Promise((resolve, reject)=> {
        console.log(res)
        resolve('ok2')
    })
},(e)=> {
    console.log(e, 'error1')
}).then((res)=> {
    console.log(res)
    return new Promise((reolve,reject)=> {
        reject('notok1')
    })
},e=> {
    console.log(e, 'error2')
}).then(res=> {
    console.log(res)
}, e=> {
    console.log(e, 'error3')
})

// ok1
// ok2
// notok1 error3

3. then 函数的回调函数中发生错误

如果错误没有被就近处理, 则会沿着链式调用的链条一直向下传递, 直到找到一个错误处理的 onRejected 回调函数, 再根据 onRejected 的返回值确定后边的链式调用的执行情况。 跑错之后, onRejected 回调函数之前的所有代码, 都无法被执行, 参考下例:

const p = new Promise((resolve, reject)=> {
    setTimeout(()=> {
        reject('notok1')  
    },1000)
})
p.then(res=> {
    console.log(res)
}).then(res=> [
    console.log(res)
]).then(res=> {
    console.log(res)
},e=> {
    console.log(e)
    return 'caught error'
}).then(res=>{
    console.log('success :' , res)
},e=>console.log(e))

// 输出
// notok1
// success : caught error

实现代码如下

// promise 的三种状态, 等待、完成(成功)、拒绝(失败)
// 也可以根据promise的状态划分成 已决和未决两种状态, 已决 : FULFILLED、REJECTED, 未决: PENDING
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

const isPromise = p => typeof p.then === "function"

// 解析 x 与 promise2 , 最终确定 promise2 的状态 
const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 === x) return reject(new TypeError('循环调用了同一个未决的 promise'))
    // 定义一个哨兵变量, 防止 promise 的状态在已决后发生改变
    let isCalled
    if (typeof x === 'object' && x !== null || typeof x === 'function') {
        try {
            // then = x.then 将初次调用 x.then 时,取到的值缓存
            // 而多次调用 x.then 可能发生属性读取错误( 虽然一般不会)
            // 所以此处直接调用 then.call, 而不是再次去读取 x.then
            const then = x.then
            // 可以判断 x 为一个promise, 即 resolve(new Promise()) 这种情况
            if ('function' === typeof then) {
                // x 是一个 promise, promise2 的状态最终取决有 x 这个 promise 的状态
                // 所以要调用属于 x 的 then 函数, 才会进入 onFulfilled 或者 onRjected, 得到下一次链式调用中的回调函数的返回值
                then.call(x, y => {
                    if (isCalled) return
                    isCalled = true
                    resolvePromise(promise2, y, resolve, reject)
                }, e => {
                    if (isCalled) return
                    isCalled = true
                    reject(e)
                })
            } else {
                // x 不是一个promise , 可能是类似这种有 then 属性的普通对象 x = {then : '100'} 
                // 直接 resolve, 将状态改成 FULFILLED
                resolve(x)
            }
        } catch (error) {
            if (isCalled) return
            isCalled = true
            reject(error)
        }
    } else {
        // 排除掉 x 为一个 promise 的可能性, 直接resolve(x)
        resolve(x)
    }
}

// Promise 类
class Promise {
    constructor(executor) {
        // promise 初始状态为 PENDING
        this.status = PENDING
        this.value = null
        this.reason = null
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
        const resolve = (value) => {

            // 递归解析 resolve 的参数, 直到参数不为 promise 的实例
            if(value instanceof Promise) {
                return value.then(resolve,reject)
            }
            if (this.status === PENDING) {
                this.status = FULFILLED
                this.value = value
                this.onFulfilledCallbacks.forEach(fn => fn())
            }
        }
        const reject = (reason) => {
            if (this.status === PENDING) {
                this.status = REJECTED
                this.reason = reason
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }
        // 立即执行 executor, 捕获错误后直接变成拒绝态
        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }

    static resolve (value) {
        return new Promise(resolve => resolve(value))
    }
    static reject(reason) {
        return new Promise((resolve,reject)=> reject(reason))
    }
    static all(promises) {
        return new Promise((resolve, reject)=> {
            
            let arr = [], index = 0
            const processData = (i, data)=> {
                arr[i] = data
                if(++index >= promises.length) {
                    resolve(arr)
                }
            }
    
            for(let i =0 ; i< promises.length; i++) {
                if(isPromise(promises[i])) {
                    promises[i].then(data=> {
    
                        processData(i,data)
                    },reason=> {
                        reject(reason)
                    })
                }else {
                    processData(i, promises[i])
                }
            }
        })

    }

    static race(promises) {
        return new Promise((resolve, reject)=> {
            for(let i = 0; i < promises.length; i++) {
                if(isPromise(promises[i])) {
                    promises[i].then(resolve,reject)
                }else {
                    resolve(promises[i])
                }
            }
        })
    }
    // then 函数返回一个新的 Promise 实例, 实现链式调用
    // 这个新的 promise 会采用当前 promise 的状态
    then(onFulfilled, onRejected) {
        // 如果 onFulfilled 不是一个函数, 则将 resolve 的参数传递给下个then 函数的 onFulfilled 作为参数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        // 如果 onRjected 不是一个函数, 则将错误抛出, 传递到下一个 then 函数的 onRjected 作为参数
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }

        const _this = this
        const promise2 = new Promise((resolve, reject) => {
            // 如果当前实例状态是 FULFILLED, 则调用成功的回调函数,  即 then(onFulfilled, onRejected) 中的 onFulfilled
            // 然后将 onFulfilled 的返回值, 继续用 resolvePromise 解析,直到解析到一个不为 promise 的普通值, 或者解析出错
            const getFulfilled = () => {
                const x = onFulfilled(_this.value)
                resolvePromise(promise2, x, resolve, reject)
            }
            const getRejected = () => {
                const x = onRejected(_this.reason)
                resolvePromise(promise2, x, resolve, reject)
            }
            // 此处设置 promise2 的状态, 由于此段代码包含在 promise2 实例化的过程中,因此, 无法获取 promise2 的实例
            // 故而将 resolvePromise 函数 (解析 promise2 和 当前实例的 then 函数的回调函数的返回值 )放在一个延时定时器中
            // 使得执行 resolvePromise 的任务放在任务队列的最后, 从而确保 先实例化 promise2 成功
            // 然后根据当前实例的状态,  得到当前实例回调函数的返回值 x , 并将 x 传入 resolvePromise 进行统一解析处理
            const getAsyncTaskResult = f => {
                setTimeout(() => {
                    try {
                        f()
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            }
            // 根据当前实例的状态制定不同的策略 :
            // 1. 当前实例为 FULFILLED 状态时,则直接调用 onFulfilled , 并将结果交由 resolvePromise 处理 
            // 2. 当前实例为 REJECTED 状态时,则直接调用 onRejected , 并将结果交由 resolvePromise 处理 
            // 3.1 当前实例为 PENDING 状态时, 则将 onRjected 和 onFulfilled 的调用缓存在一个任务队列中
            // 3.2 然后等待当前实例成功(resolve)或者失败(reject)
            // 3.3 由于在构造函数中订阅了 resolve 和 reject, 所以当前实例一旦发布状态, 对应的任务队列将会按照序被调用
            const stratagies = {
                PENDING() {
                    _this.onFulfilledCallbacks.push(() => getAsyncTaskResult(getFulfilled))
                    _this.onRejectedCallbacks.push(() => getAsyncTaskResult(getRejected))
                },
                FULFILLED() {
                    getAsyncTaskResult(getFulfilled)
                },
                REJECTED() {
                    getAsyncTaskResult(getRejected)
                },
            }
            Reflect.has(stratagies, this.status) && stratagies[this.status]()
        })
        return promise2
    }
    // catch 是一个只有失败回调的then函数
    catch(errorCallback) {
        this.then(null, errorCallback)
    }
    // finally 
    // 不管上一个 promise 成功还是失败, finally 的回调函数都会执行
    // 不改变 then 函数两个回调函数的参数, 仍然用的是上一次链式调用的最终结果
    finally(callback) {
        return this.then(value=> {
            return Promise.resolve( allback()).then(()=> value)
            
        }, reason=> {
            return Promise.resolve(callback()).then(()=> {throw reason})
        })
    }
}

// 测试代码
// 安装 : npm i promises-aplus-tests -g
// 运行 : promises-aplus-tests filename 
Promise.defer = Promise.deferred = function () {
    const dfd = {}
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve
        dfd.reject = reject
    })
    return dfd
}

module.exports = Promise
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值