手撕Promise

此文适合有Promise基础的同学阅读~~~

构造函数写法

/**
 * 构造函数
 * @param executor
 * @constructor
 */
function Promise(executor) {
    // Promise实例的初始状态设置为'pending'
    this.PromiseState = 'pending'
    // Promise实例的初始值设置为null
    this.PromiseResult = null
    // Promise.then可以注册多个回调,当resolve()在异步代码中执行时,回调函数在这里保存
    this.callbacks = []
    // Promise自带的resolve函数
    function resolve(data) {
        // Promise实例的状态一旦由pending改变之后,不可以再变
        if (this.PromiseState !== 'pending') return
        // 执行resolve时,将Promise实例的状态修改为'fulfilled'
        this.PromiseState = 'fulfilled'
        // 执行resolve时,将Promise实例的值修改为resolve函数的参数
        this.PromiseResult = data
        // 当resolve在同步代码中执行时,将then方法中注册的回调函数放入任务队列,避免回调函数同步执行
        // 本应是放入微任务队列,这里用setTimeout放入宏任务队列凑合一下
        setTimeout(() => {
            // 将then方法中注册的成功回调函数挨个执行
            this.callbacks.forEach(item => {
                item.onResolved(this.PromiseResult)
            })
        })
    }
    // Promise自带的reject函数
    function reject(data) {
        // Promise实例的状态一旦由pending改变之后,不可以再变
        if (this.PromiseState !== 'pending') return
        // 执行resolve时,将Promise实例的状态修改为'rejected'
        this.PromiseState = 'rejected'
        // 执行resolve时,将Promise实例的值修改为reject函数的参数
        this.PromiseResult = data
        setTimeout(() => {
            // 将then方法中注册的失败回调函数挨个执行
            this.callbacks.forEach(item => {
                item.onRejected(this.PromiseResult)
            })
        })
    }
    try {
        // new Promise时立即执行构造函数参数中的executor函数,注意这里的this
        // 如果不将executor参数中函数的this绑定到Promise实例对象的话,resolve和reject执行时函数中的this会指向window
        // 构造函数中的this指向实例对象,因此这里bind(this)的作用是让resolve和reject执行时函数中的this指向Promise实例对象
        executor(resolve.bind(this), reject.bind(this))
    } catch (e) {
        // 如果executor函数中抛出错误,相当于执行reject函数,Promise实例对象的状态变为'rejected'
        reject.call(this, e)
    }
}

/**
 * Promise的then方法,返回一个新的Promise对象
 * @param onResolved
 * @param onRejected
 * @returns {Promise}
 */
Promise.prototype.then = function (onResolved, onRejected) {
    // then方法可以不传参,默认成功和失败的回调
    if (typeof onRejected !== 'function') {
        onRejected = err => {
            throw err
        }
    }
    if (typeof onResolved !== 'function') {
        onResolved = data => data
    }
    return new Promise((resolve, reject) => {
        // 封装回调函数
        let callback = (callbackOn) => {
            try {
                // 判断回调函数的执行结构
                let result =  callbackOn(this.PromiseResult)
                // 如果回调函数的执行结果返回Promise对象,则根据返回的Promise对象的状态修改then方法返回的Promise对象的状态和值
                if (result instanceof Promise) {
                    result.then(v => {
                        resolve(v)
                    }, r => {
                        reject(r)
                    })
                // 如果回调函数的执行结果返回值不是Promise对象,则then方法返回一个状态为fulfilled的Promise对象,值为回调函数的返回值
                } else {
                    resolve(result)
                }
                // 如果回调函数中报错,则then方法返回一个状态为rejected的Promise对象,值为错误信息
            } catch (e) {
                reject(e)
            }
        }
        // 一旦调用then方法的Promise对象状态变为fulfilled,将成功的回调放入任务队列,等待执行
        // 本应是放入微任务队列,这里用setTimeout放入宏任务队列凑合一下
        if (this.PromiseState === 'fulfilled') {
            setTimeout(() => {
                callback(onResolved)
            })

        }
        // 一旦调用then方法的Promise对象状态变为rejected,将失败的回调放入任务队列,等待执行
        // 本应是放入微任务队列,这里用setTimeout放入宏任务队列凑合一下
        if (this.PromiseState === 'rejected') {
            setTimeout(() => {
                callback(onRejected)
            })
        }
        // 如果执行到then方法时调用then方法的Promise对象的状态还是pending(在Promise对象的executor函数中执行了异步操作),则将回调函数保存起来,
        // 等Promise对象的状态改变时再执行(详见构造函数中定义的resolve和reject函数)
        if (this.PromiseState === 'pending') {
            this.callbacks.push({
                onResolved: () => {
                    callback(onResolved)
                },
                onRejected: () => {
                    callback(onRejected)
                }
            })
        }
    })
}
/**
 * Promise的catch方法,跟then方法中执行失败的回调没有区别
 * @param onRejected
 * @returns {Promise}
 */
Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
}
/**
 * Promise的resolve方法
 * @param value
 * @returns {Promise}
 */
Promise.resolve = function (value) {
    return new Promise((resolve, reject) => {
        // 如果参数是一个Promise对象
        if (value instanceof Promise) {
            // 根据参数Promise对象的状态确定返回的Promise对象的状态和值
            value.then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
            // 如果参数不是一个Promise对象,则返回一个状态为fulfilled的Promise对象,值为resolve函数的参数
        } else {
            resolve(value)
        }
    })
}
/**
 * Promise的reject方法,返回一个Promise实例对象,并将其状态改为rejected,值改为reject函数的参数
 * @param reason
 * @returns {Promise}
 */
Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason)
    })
}
/**
 * Promise的all方法,返回一个Promise实例对象,状态为fulfilled,值为数组(参数中所有的Promise实例的状态都变为了fulfilled的情况下),
 * 状态为rejected,值为参数中最先执行reject函数的Promise实例的值
 * @param promises
 * @returns {Promise}
 */
Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        let count = 0
        let arr = []
        for (let i = 0; i < promises.length; i++) {
            promises[i].then((res) => {
                // 一旦数组中的某个Promise的状态变为'fulfilled',计数器加1,直到数组中所有的Promise对象状态都变成'fulfilled',
                // 将返回的Promise对象的状态变为’fulfilled', 值变为数组中所有的Promise对象的值构成的数组(按照先后顺序)
                count++
                arr[i] = res
                if (count === promises.length) {
                    resolve(arr)
                }
            }, (err) => {
                // 一旦数组中的某个Promise的状态变为'rejected',将返回的Promise对象的状态变为'rejected',
                // 值变为数组中状态最先变为'rejected'的Promise对象的值
                reject(err)
            })
        }
    })
}
/**
 * Promise的race方法,传入Promise对象数组,返回一个新的Promise对象
 * @param promises
 * @returns {Promise}
 */
Promise.race = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(res => {
                // 一旦数组中的某个Promise的状态变为'fulfilled',将返回的Promise对象的状态变为’fulfilled',
                // 值变为数组中状态最先变为'fulfilled'的Promise对象的值
                resolve(res)
            }, err => {
                // 一旦数组中的某个Promise的状态变为'rejected',将返回的Promise对象的状态变为'rejected',
                // 值变为数组中状态最先变为'rejected'的Promise对象的值
                reject(err)
            })
        }
    })
}

封装成类

class Promise {
    constructor(executor) {
        this.PromiseState = 'pending'
        this.PromiseResult = null
        this.callbacks = []
        function resolve(data) {
            if (this.PromiseState !== 'pending') return
            this.PromiseState = 'fulfilled'
            this.PromiseResult = data
            setTimeout(() => {
                this.callbacks.forEach(item => {
                    item.onResolved(this.PromiseResult)
                })
            })
        }
        function reject(data) {
            if (this.PromiseState !== 'pending') return
            this.PromiseState = 'rejected'
            this.PromiseResult = data
            setTimeout(() => {
                this.callbacks.forEach(item => {
                    item.onRejected(this.PromiseResult)
                })
            })
        }
        try {
            executor(resolve.bind(this), reject.bind(this))
        } catch (e) {
            reject.call(this, e)
        }
    }
    then(onResolved, onRejected) {
        if (typeof onRejected !== 'function') {
            onRejected = err => {
                throw err
            }
        }
        if (typeof onResolved !== 'function') {
            onResolved = data => data
        }
        return new Promise((resolve, reject) => {
            let callback = (callbackOn) => {
                try {
                    let result =  callbackOn(this.PromiseResult)
                    if (result instanceof Promise) {
                        result.then(v => {
                            resolve(v)
                        }, r => {
                            reject(r)
                        })
                    } else {
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }
            if (this.PromiseState === 'fulfilled') {
                setTimeout(() => {
                    callback(onResolved)
                })

            }
            if (this.PromiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected)
                })
            }
            if (this.PromiseState === 'pending') {
                this.callbacks.push({
                    onResolved: () => {
                        callback(onResolved)
                    },
                    onRejected: () => {
                        callback(onRejected)
                    }
                })
            }
        })
    }
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    static resolve(value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v)
                }, r => {
                    reject(r)
                })
            } else {
                resolve(value)
            }
        })
    }
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }
    static all(promises) {
        return new Promise((resolve, reject) => {
            let count = 0
            let arr = []
            for (let i = 0; i < promises.length; i++) {
                promises[i].then((res) => {
                    count++
                    arr[i] = res
                    if (count === promises.length) {
                        resolve(arr)
                    }
                }, (err) => {
                    reject(err)
                })
            }
        })
    }
    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(res => {
                    resolve(res)
                }, err => {
                    reject(err)
                })
            }
        })
    }
}

不够清楚或者有误的地方欢迎评论区指正~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值