手写promise

实现目标

  • 定义promise构造函数
  • 实现then方法
  • then方法的链式调用
  • 实现catch方法
  • 实现finally方法
  • 实现resolve静态方法
  • 实现all静态方法

代码

class MPromise {
    constructor(handler) {
        // 保存promise的状态
        this.status = 'PENDING'
        // 将then()中resolve方法加入到队列中,当执行promise状态变为“成功态”后调用
        this.resolveHandlers = []
        this.rejectHandlers = []
        // 保存finally()回调函数,当promise状态改变后调用
        this.finallyHandlers = []
        // 将_resolve()中的this指向绑定到当前实例对象
        handler(this._resolve.bind(this), this._reject.bind(this))
    }

    _resolve(val) {
        // 状态改变后,不能再执行
        if (this.status != 'PENDING') return
        this.status = 'FULFILLED'

        this._observer(() => {
            // 状态改变后,从事件队列(FIFO)中获取循环获取事件执行
            let handler;
            while (handler = this.resolveHandlers.shift()) {
                handler(val)
            }
            while (handler = this.finallyHandlers.shift()) {
                handler(val)
            }
        })
    }

    _reject(val) {
        if (this.status != 'PENDING') return
        this.status = 'REJECTED'

        this._observer(() => {
            let handler;
            while (handler = this.rejectHandlers.shift()) {
                handler(val)
            }
            while (handler = this.finallyHandlers.shift()) {
                handler(val)
            }
        })
    }

    // 将事件对象放入到MutationObserver微任务中,目的是保证then()中事件先于setTimeout等宏任务执行
    _observer(callback) {
        let observer = new MutationObserver(() => {
            callback()
            observer.disconnect()
        })
        observer.observe(document.body, {
            attributes: true
        })
        document.body.setAttribute('mb', Math.random())
    }

    then(resolveCb, rejectCb) {
        return new MPromise((resolve, reject) => {
            if (resolveCb && typeof resolveCb == "function") {
                // 将resolve事件放入到resolve队列中,目的是保证promise状态改变为“成功态”后,再执行
                this.resolveHandlers.push(val => {
                    // 链式调用时,获取resolve事件返回值,并传入到下次then()中
                    val = resolveCb(val)
                    if (val && val instanceof MPromise) {
                        return val.then(resolve, reject)
                    }
                    resolve(val)
                })
            }
            if (rejectCb && typeof rejectCb == "function") {
                this.rejectHandlers.push(val => {
                    val = rejectCb(val)
                    if (val && val instanceof MPromise) {
                        return val.then(resolve, reject)
                    }
                    reject(val)
                })
            }
        })
    }

    // 类似于then()中的第二个参数
    catch(cb) {
        return this.then(null, cb)
    }

    // 不能立即执行,放入事件队列中,等待promise状态改变后再执行
    finally(cb) {
        this.finallyHandlers.push(cb)
    }

    static resolve(val) {
        return new MPromise(resolve => {
            resolve(val)
        })
    }

    static all(it) {
        let len = it.length
        return new MPromise(resolve => {
            let vals = []
            let n = 0
            for (let i = 0; i < len; i++) {
                it[i].then(val => {
                    // 保证返回数组中顺序和promise一致

                    vals[i] = val
                    n++
                    // 当数组中promise对象全部执行完成后,再调用resolve()
                    if (n == len) {
                        resolve(vals)
                    }
                })
            }
        })
    }
}

测试

实现promise构造函数
/**
 *  1. 构造函数内部代码立即执行
 *  2. 构造函数一个方法,方法中接受两个函数作为参数
 *      - resolve:将promise状态变为“成功态”
 *      - reject:将promise状态变为“失败态”
 *  3. promise状态一旦改变就不能再次更改
 */
let p = new MPromise((resolve, reject) => {
    console.log("promise")
    
    resolve(100)
    // reject('error')
})
实现then方法
/**
 *  1. 接受两个回调函数作为参数
 *      - 第一个参数:promise状态变为“成功”时调用
 *      - 第二个参数:promise状态变为“失败”时调用
 *  2. 回调函数中可接受调用resolve()、reject()方法时,传递的参数
 *  3. then()中执行顺序先于setTimeout异步函数
 */
console.log('1111')
setTimeout(() => {
    console.log("外部setTimeout执行")
})

let p = new MPromise((resolve, reject) => {
    console.log("promise")
    resolve(100)
})
p.then(res => {
    console.log('then方法中的返回值:', res)
}, err => {
    console.log('then方法中返回的错误:', err)
})
then方法的链式调用
/**
 *  1. then方法返回一个promise对象,可实现方法的链式调用
 *  2. then方法接受参数函数中,可返回值/Promise对象作为再次then()回调函数的参数
 *      - 返回值:封装为promise对象返回
 *      - 返回promise对象:调用then()后返回
 * 
 */
let p = new MPromise((resolve, reject) => {
    console.log("promise")
    resolve(100)
})
p.then(res => {
    console.log('then方法中的返回值:', res)
    // return 200
    return new MPromise((resolve, reject) => {
        resolve(200)
    })
}).then(res => {
    console.log("第二次then方法中的返回值:", res)
})
实现catch方法
/**
 *  1. 只实现了捕获调用reject()的错误,未实现new Error()中的错误
 *  2. 回调函数中可接受调用reject()方法时,传递的参数
 */
let p = new MPromise((resolve, reject) => {
    console.log("promise")
    resolve(100)
})
p.then(res => {
    console.log('then方法中的返回值:', res)
    return new MPromise((resolve, reject) => {
        reject('error')
    })
}).catch(err => {
    console.log('catch中捕获的错误:', err)
})
实现finally方法
/**
 *  1. 接受回调函数作为参数,promise状态改变后执行
 */
 let p = new MPromise((resolve, reject) => {
    console.log("promise")
    resolve(100)
})
p.then(res => {
    console.log('then方法中的返回值:', res)
    return new MPromise((resolve, reject) => {
        reject('error')
    })
}).catch(err => {
    console.log('catch中捕获的错误:', err)
}).finally(() => {
    console.log('执行finally')
})
实现resolve静态方法
/**
 *  1. 返回一个“成功态”的promise对象
 */
let p = MPromise.resolve(100)
console.log(p)
实现all静态方法
/**
 *  1. 接受一个promise数组
 *  2. 数组中promise全部调用完成后,返回一个包含promise数组结果的promise对象
 */
let p1 = new MPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(100)
    }, 500)
})
let p2 = new MPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(200)
    }, 1000)
})
let p3 = new MPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(300)
    }, 100)
})
MPromise.all([p1, p2, p3]).then(vals => {
    console.log(vals)
})
posted @ 2022-04-13 19:40  孟冰er  阅读(21)  评论(0编辑  收藏  举报