likes
comments
collection
share

一文学会手写Promise

作者站长头像
站长
· 阅读数 64

什么是Promise

在开始编码之前,我们先来看一下什么是Promise,话不多说直接上MDN的描述。

一文学会手写Promise 看完MDN的描述我们已经知道Promise原来是一个对象,可以表示异步操作的成功或失败。

PromiseA+规范

Promise的实现要符合PromiseA+规范,那我们就先看一下什么是PromiseA+规范。

一文学会手写Promise 从规范中我们了解到,promise是一个对象,要包含一个then方法。具体的内容感兴趣的可以去 原文 了解一下。

开始动手了

// 定义promise状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'


/**
 * 创建MyPromise类
 */
class MyPromise {
    /**
     * 接受一个执行器
     * @param { function } executor 
     */
    constructor(executor){
        // 默认状态为pending
        this.state = PENDING
        this.value = undefined
        executor(this._resolve.bind(this),this._reject.bind(this))
    }

    /**
     * 更改promise状态为成功
     * @param {*} data 
     */
    _resolve(data) {
        this.state = FULFILLED
        this.value = data
    }

    /**
     * 更改状态为失败
     * @param {*} reason 
     */
    _reject(reason) {
        this.state = REJECTED
        this.value = reason
    }
}

我们已经可以通过MyPromise这个类来创建promise实例了,接下来我们实现then方法并完善一下这个类。

/**
 * 创建MyPromise类
 */
class MyPromise {
    /**
     * 接受一个执行器
     * @param { function } executor 
     */
    constructor(executor){
        // 默认状态为pending
        this.state = PENDING
        this.value = undefined
        this.handlers = []
        executor(this._resolve.bind(this),this._reject.bind(this))
    }


    /**
     * 变更状态的方法
     */
    _changeState(state,value) {
        if(this.state!==PENDING) { return }
        this.state = state
        this.value = value
    }

    /**
     * 往任务队列添加任务
     */

    _pushHandler(executor,state,resolve,reject){
        this.handlers.push({
            executor,state,resolve,reject
        })
    }

    /**
     * 更改promise状态为成功
     * @param {*} data 
     */
    _resolve(data) {
        this._changeState(FULFILLED,data)
    }

    /**
     * 更改状态为失败
     * @param {*} reason 
     */
    _reject(reason) {
        this._changeState(REJECTED, reason)
    }

    /**
     * 符合Promise A+规范的then方法
     */

    then(onFulfilled,onRejected){
        // then方法返回一个promise执行
        return new MyPromise((resolve,reject) => {
            this._pushHandler(onFulfilled,FULFILLED,resolve,reject)
            this._pushHandler(onRejected,REJECTED,resolve,reject)
        })
    }
}

ok,then方法已经添加了,现在已经可以把任务添加到存储任务的数组了,你是不不是以为这就大功告成了。NONONO,我们还少了最重要的一步,任务的执行。说到任务的执行,那就离不了宏任务和微任务的概念了,让我们先来看一下什么是宏任务和微任务吧。

宏任务与微任务

我们学习js听的最多的一句话应该就是js是单线程执行了。那既然是单线程执行遇到比较耗时的任务时怎么处理呢,总不能一直阻塞吧。为了解决这个问题,js划分了同步任务和异步任务。异步任务又分为宏任务和微任务。 常见的任务创建方式:

  • 宏任务: script(整体代码块)、settimeout、setInterval、setImmediate(node环境)
  • 微任务:MutationObserver(浏览器环境)、 process.nextTick(node环境)、queueMicrotask

这里对异步机制介绍的比较粗陋,感兴趣的同学可以移步 js执行机制去了更多。

实现任务执行

我们先来写一个执行微任务的辅助函数和一个判断是否是promise的函数

/**
 * 接收一个函数放入微队列执行
 * @param { function } callback 
 */
function runMincroTask(callback) {
    if(queueMicrotask) {
        queueMicrotask(callback)
    } else if(process&&process.nextTick){
        process.nextTick(callback)
    } else if(MutationObserver){
        let p = document.createElement('p')
        const ob = new MutationObserver(callback)
        ob.observe({
            childList: true
        })
        p.innerHTML = '1'
    } else {
        setTimeout(callback,0)
    }
}


/**
 * 接受一个任意参数,判断是否为promise
 * @param {*} obj 
 * @returns 
 */
function isPromise(obj) {
    return !!(obj&&typeof obj==='object' && typeof obj.then === 'function' )
}

准备工作搞定了,接下来我们来实现任务执行的方法。

 /**
     * 任务执行方法
     */
    _runHandler() {
        if(this.state===PENDING) { return }
        // 拿出任务队列的每一项执行
        while(this.handlers[0]) {
            const handle = this.handlers[0]
            this._runOneHandler(handle)
            this.handlers.shift()
        }
    }

    /**
     * 执行任务队列的每一项任务
     */
    _runOneHandler({executor,state,resolve,reject}){
        // 把任务放入微任务队列执行
        runMincroTask(() => {
            if(state!==this.state) { return }
            if(typeof executor !== 'function') {
                this.state === FULFILLED ? resolve(this.value) : reject(this.value)
                return
            }
            try {
                const result = executor(this.value)
                if(isPromise(result)) {
                    result.then(resolve,reject)
                } else {
                    resolve(this.value)
                }
            } catch (error) {
                reject(this.value)
                console.log(error)
            }
        })
    }

呼~,任务执行的方法搞定了。接下来我们在状态改变和then方法中添加调用。

/**
     * 变更状态的方法
     */
    _changeState(state,value) {
        if(this.state!==PENDING) { return }
        this.state = state
        this.value = value
        // 状态变更调用任务执行
        this._runHandler()
    }
    
    
    then(onFulfilled,onRejected){
        // then方法返回一个promise执行
        return new MyPromise((resolve,reject) => {
            this._pushHandler(onFulfilled,FULFILLED,resolve,reject)
            this._pushHandler(onRejected,REJECTED,resolve,reject)
            this._runHandler()
        })
    }

验证

大功告成,接下来我们来验证是否好使吧。

const p = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 2000)
})
const p1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        reject(2)
    }, 1000) 
})

Promise.any([
    p,p1
]).then((first) => {  // 只要有一个 fetch() 请求成功
  console.log(first);
}).catch((error) => { // 所有三个 fetch() 全部请求失败
  console.log(error);
});

一文学会手写Promise

利用原生Promise 和 MyPromise进行测试,最终结果输出正确。至此一个符合Promise A+规范的 Promise就完成了。

catch方法实现

/**
     * 处理任务失败的情况
     * @param {*} onRejected 
     * @returns 
     */
    catch(onRejected) {
        return this.then(null ,onRejected)
    }

finally方法实现

/**
 * 不论成功或失败都会执行的方法
 * @param {*} onSetteld 
 */
finally(onSetteld){
    return this.then(data => {
        onSetteld()
        return data
    }, reason => {
        onSetteld()
        throw reason
    })
}

resolve和reject方法实现

/**
     * 
     * @param {*} obj 需要转为promise的对象
     */
    static resolve(obj) {
        return new MyPromise((resolve,reject) => {
            if(obj instanceof MyPromise) {
                return obj
            }
            if(isPromise(obj)) {
                obj.then(resolve,reject)
            } else {
                resolve(obj)
            }
        })
    }

    /**
     * 返回一个状态为被拒绝的promise
     * @param {*} reason 失败原因
     * @returns 
     */
    static reject(reason) {
        return new MyPromise((resolve,reject) => {
            reject(reason)
        })
    }

all方法实现

/**
     * 接受一个具有interator属性的值,
     * @param { interator } arr 
     */
    static all(arr) {
        return new MyPromise((resolve, reject) => {
            try {
                let count = 0
                let fulfilledCount = 0
                let results = []
                for (const item of arr) {
                    let i = count
                    count++
                    MyPromise.resolve(item).then(data => {
                        fulfilledCount++
                        results[i] = data
                        if (count === fulfilledCount) {
                            resolve(results)
                        }
                    }, reject)
                }
                if (count === 0) {
                    resolve([])
                }
            } catch (err) {
                reject(err)
            }

        })
    }

allSettled方法实现

/**
     * 接受一个包含多个promise的参数
     * 所有promise已决后返回结果
     * @param { interator } arr 
     */
    static allSettled(arr) {
        return new MyPromise((resolve,reject) => {
            let results = []
            for (const p of arr) {
                results.push( MyPromise.resolve(p).then(
                    data=> ({ status: FULFILLED, value:data })),
                    reason => ({ status: REJECTED, reason })
                 )
            }
            return MyPromise.all(results)
        })
    }

race方法实现

/**
     * 接受一个包含多个promise的参数
     * 返回最先完成的promise结果,不论成功还是失败
     * @param { interator } arr 
     */
    static race(arr) {
        return new MyPromise((resolve,reject) => {
            for (const item of arr) {
                MyPromise.resolve(item).then(resolve,reject)
            }
        })
    }

any方法实现

/**
 * 接受一个包含多个promise的参数
 * 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
 * 如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
 * @param { interator } arr 
 */
static any(arr) {
    return new MyPromise((resolve,reject) => {
        let rejectCount = 0
        let errResults = []
        for (const item of arr) {
            MyPromise.resolve(item).then(resolve,reason => {
                rejectCount++
                errResults[rejectCount] = { reason }
                if(errResults===arr.length) {
                    reject(errResults)
                }
            })
        }
        if(rejectCount===0) {
            resolve([])
        }
    })
}

全部完结啦!!!!!

贴上完整代码


// 定义promise状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

/**
 * 接收一个函数放入微队列执行
 * @param { function } callback 
 */
function runMincroTask(callback) {
    if (queueMicrotask) {
        queueMicrotask(callback)
    } else if (process && process.nextTick) {
        process.nextTick(callback)
    } else if (MutationObserver) {
        let p = document.createElement('p')
        const ob = new MutationObserver(callback)
        ob.observe({
            childList: true
        })
        p.innerHTML = '1'
    } else {
        setTimeout(callback, 0)
    }
}

/**
 * 接受一个任意参数,判断是否为promise
 * @param {*} obj 
 * @returns 
 */
function isPromise(obj) {
    return !!(obj && typeof obj === 'object' && typeof obj.then === 'function')
}

/**
 * 创建MyPromise类
 */
class MyPromise {
    /**
     * 接受一个执行器
     * @param { function } executor 
     */
    constructor(executor) {
        // 默认状态为pending
        this.state = PENDING
        this.value = undefined
        this.handlers = []
        try {
            executor(this._resolve.bind(this), this._reject.bind(this))
        } catch (error) {
            this._reject(error)
            console.log(error)
        }

    }


    /**
     * 变更状态的方法
     */
    _changeState(state, value) {
        if (this.state !== PENDING) { return }
        this.state = state
        this.value = value
        // 状态变更调用任务执行
        this._runHandler()
    }

    /**
     * 往任务队列添加任务
     */

    _pushHandler(executor, state, resolve, reject) {
        this.handlers.push({
            executor, state, resolve, reject
        })
    }

    /**
     * 任务执行方法
     */
    _runHandler() {
        if (this.state === PENDING) { return }
        // 拿出任务队列的每一项执行
        while (this.handlers[0]) {
            const handle = this.handlers[0]
            this._runOneHandler(handle)
            this.handlers.shift()
        }
    }

    /**
     * 执行任务队列的每一项任务
     */
    _runOneHandler({ executor, state, resolve, reject }) {
        // 把任务放入微任务队列执行
        runMincroTask(() => {
            if (state !== this.state) { return }
            if (typeof executor !== 'function') {
                this.state === FULFILLED ? resolve(this.value) : reject(this.value)
                return
            }
            try {
                const result = executor(this.value)
                if (isPromise(result)) {
                    result.then(resolve, reject)
                } else {
                    resolve(this.value)
                }
            } catch (error) {
                reject(this.value)
                console.log(error)
            }
        })
    }

    /**
     * 更改promise状态为成功
     * @param {*} data 
     */
    _resolve(data) {
        this._changeState(FULFILLED, data)
    }

    /**
     * 更改状态为失败
     * @param {*} reason 
     */
    _reject(reason) {
        this._changeState(REJECTED, reason)
    }

    /**
     * 符合Promise A+规范的then方法
     */

    then(onFulfilled, onRejected) {
        // then方法返回一个promise执行
        return new MyPromise((resolve, reject) => {
            this._pushHandler(onFulfilled, FULFILLED, resolve, reject)
            this._pushHandler(onRejected, REJECTED, resolve, reject)
            this._runHandler()
        })
    }

    /**
     * 处理任务失败的情况
     * @param {*} onRejected 
     * @returns 
     */
    catch(onRejected) {
        return this.then(null, onRejected)
    }

    /**
     * 不论成功或失败都会执行的方法
     * @param {*} onSetteld 
     */
    finally(onSetteld) {
        return this.then(data => {
            onSetteld()
            return data
        }, reason => {
            onSetteld()
            throw reason
        })
    }

    /**
     * 
     * @param {*} obj 需要转为promise的对象
     */
    static resolve(obj) {
        return new MyPromise((resolve, reject) => {
            if (obj instanceof MyPromise) {
                return obj
            }
            if (isPromise(obj)) {
                obj.then(resolve, reject)
            } else {
                resolve(obj)
            }
        })
    }

    /**
     * 返回一个状态为被拒绝的promise
     * @param {*} reason 失败原因
     * @returns 
     */
    static reject(reason) {
        return new MyPromise((resolve, reject) => {
            reject(reason)
        })
    }

    /**
     * 接受一个具有interator属性的值,
     * @param { interator } arr 
     */
    static all(arr) {
        return new MyPromise((resolve, reject) => {
            try {
                let count = 0
                let fulfilledCount = 0
                let results = []
                for (const item of arr) {
                    let i = count
                    count++
                    MyPromise.resolve(item).then(data => {
                        fulfilledCount++
                        results[i] = data
                        if (count === fulfilledCount) {
                            resolve(results)
                        }
                    }, reject)
                }
                if (count === 0) {
                    resolve([])
                }
            } catch (err) {
                reject(err)
            }

        })
    }


    /**
     * 接受一个包含多个promise的参数
     * 所有promise已决后返回结果
     * @param { interator } arr 
     */
    static allSettled(arr) {
        return new MyPromise((resolve,reject) => {
            let results = []
            for (const p of arr) {
                results.push( MyPromise.resolve(p).then(
                    data=> ({ status: FULFILLED, value:data })),
                    reason => ({ status: REJECTED, reason })
                 )
            }
            return MyPromise.all(results)
        })
    }

    /**
     * 接受一个包含多个promise的参数
     * 返回最先完成的promise结果,不论成功还是失败
     * @param { interator } arr 
     */
    static race(arr) {
        return new MyPromise((resolve,reject) => {
            for (const item of arr) {
                MyPromise.resolve(item).then(resolve,reject)
            }
        })
    }
    /**
     * 接受一个包含多个promise的参数
     * 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
     * 如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
     * @param { interator } arr 
     */
    static any(arr) {
        return new MyPromise((resolve,reject) => {
            let rejectCount = 0
            let errResults = []
            for (const item of arr) {
                MyPromise.resolve(item).then(resolve,reason => {
                    rejectCount++
                    errResults[rejectCount] = { reason }
                    if(errResults===arr.length) {
                        reject(errResults)
                    }
                })
            }
            if(rejectCount===0) {
                resolve([])
            }
        })
    }
}



转载自:https://juejin.cn/post/7265329025899855927
评论
请登录