zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    11.组件-组件中的data和methods
    09.组件-创建组件的方式2
    10.组件-创建组件的方式3
    07.动画-列表动画
    08.组件-创建组件的方式1
    关于苹果iBeacon官方文档解析
    IOS-代码书写规范
    IOS- 1970ms时间计算
    关于tableview顶部留白问题
    IOS-网络请求数据解析道数组程序崩溃问题
  • 原文地址:https://www.cnblogs.com/darkterror/p/14749859.html
Copyright © 2011-2022 走看看