麦西的西

V1

2023/01/17阅读:25主题:凝夜紫

手写Promise?就是这么简单

Promise 是什么

Promise 是异步编程的一种解决方案。

具体表达:
语法上来说,Promise 是一个构造函数
功能上来说,Promise 对象用来封装一个异步操作并获取其结果

为什么要用 Promise

  1. 指定回调函数的方式更加灵活
    回调函数:必须在启动异步任务前指定
    Promise: 启动异步任务,返回 Promise 对象,给 Promise 对象绑定回调函数(可以在异步任务结束后执行)

  2. 支持链式调用,解决回调地狱问题。
    回调地狱:不便于阅读,不便于异常处理
    终极解决方案:async...await(完全没有回调函数)

Promise 的常用方法

Promise(excutor) // 构造函数
Promise.prototype.then(onResolved, onRejected)
Promise.prototype.catch(onRejected)
Promise.resolve(value)
Promise.reject(reason)
Promise.all(promises)
Promise.race(promises)

Promise 的几个关键问题

  1. 抛出异常,pending 会变成 rejected

  2. 一个 Promise 指定多个成功、失败的回调,都会调用

  3. Promise.then()返回的 Promise 对象的结果由什么决定?

    1> 简单表达,由 then()指定的回调函数执行结果决定
    2> 详细表达
    a. 如果抛出异常,新 Promise 变为 rejected,reason 为抛出的异常
    b. 如果返回的是非 Promise 的任意值,新 Promise 变为 resolved,value 为返回值。
    c. 如果返回的是另一个新 Promise,此 Promise 的结果就会成为新 Promise 的结果。

  4. 如何中断 Promise 链?
    返回一个 pending 状态的 Promise 对象

  5. Promise 异常传透?
    1> 使用 then 链式调用的时候,可以在最后指定失败的回调
    2> 前面任何操作出了异常,都会传到最后失败的回调处理。

自定义 Promise 实现

/**
 * 自定义Promise
 */

 (function(window) {
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    /**
     * 构造函数
     * @param {function} excutor 执行器函数,有两个函数类型的参数:resolved, rejected
     */
    function Promise(excutor) {
        const self = this
        self.status = PENDING
        self.data = undefined // 用来保存Promise的结果
        self.callbacks = [] // 用来保存回调函数对象数组,每一项的结构为{ onResolved, onRejected }

        function resolve(value) {
            if (self.status !== PENDING) { // Promise只能执行一次
                return
            }
            self.status = RESOLVED
            self.data = value
            if (self.callbacks.length > 0) { // 如果回调函数对象数组不为空,则异步执行每一项的onResolved方法
                setTimeout(() => {
                    self.callbacks.forEach(callbackObj => {
                        callbackObj.onResolved(value)
                    })
                })
            }
        }

        function reject(reason) {
            if (self.status !== PENDING) {
                return
            }
            self.status = REJECTED
            self.data = reason
            if (self.callbacks.length > 0) {
                setTimeout(() => {
                    self.callbacks.forEach(callbackObj => {
                        callbackObj.onRejected(reason)
                    })
                })
            }
        }

        try {
            excutor(resolve, reject) // 一旦创建,立即执行
        } catch (err) { // 如果出现异常,则将该异常作为失败的结果
            reject(err)
        }
    }

    /**
     * then()方法,返回一个新Promise, 新Promise的执行结果取决于上一个Promise的返回值
     * 1. 如果抛出异常,新Promise的执行结果rejected, reason为抛出的异常
     * 2. 如果返回值是Promise, 新Promise的执行结果为上一个Promise的执行结果
     * 3. 如果返回值是非Promise, 新Promise的执行结果resolved, value为返回值
     * @param {function} onResolved Promise执行成功的回调,异步回调,接收一个参数value(Promise执行成功的结果)
     * @param {function} onRejected Promise执行失败的回调,异步回调,接收一个参数reason(Promise执行失败的结果)
     */
    Promise.prototype.then = function(onResolved, onRejected) {
        onResolved = typeof onResolved === 'function' ? onResolved : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
        const self = this
        return new Promise((resolve, reject) => {
            function handle(callback) {
                try {
                    let result = callback(self.data)
                    if (result instanceof Promise) {
                        result.then(resolve, reject)
                    } else {
                        resolve(result)
                    }
                } catch (err) {
                    reject(err)
                }
            }
            if (self.status === RESOLVED) {
                setTimeout(() => {
                    handle(onResolved)
                })
            } else if (self.status === REJECTED) {
                setTimeout(() => {
                    handle(onRejected)
                })
            } else if (self.status === PENDING) {
                self.callbacks.push({
                    onResolved: () => handle(onResolved),
                    onRejected: () => handle(onRejected)
                })
            }
        })
    }

    /**
     * catch()方法,返回一个Promise
     * @param {function} onRejected Promise执行失败的回调,异步回调,接收一个参数reason(Promise执行失败的结果)
     */
    Promise.prototype.catch = function(onRejected) {
        return Promise.then(undefined, onRejected)
    }

    /**
     * resolve()方法,返回一个Promise
     * 1. 若value为Promise, 则返回Promise的执行结果为value的执行结果
     * 2. 若value为非Promise, 则返回一个执行结果为value的成功Promise
     * @param {any} value
     */
    Promise.resolve = function(value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(resolve, reject)
            } else {
                resolve(value)
            }
        })
    }

    /**
     * reject()方法,返回一个指定结果为reason的失败的Promise
     * @param {any} reason
     */
    Promise.reject = function(reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }

    /**
     * 返回一个Promise
     * 1. 有一个失败,结果为失败的结果
     * 2. 都成功,结果为所有promise结果的数组
     * @param {array} promises
     */
    Promise.all = function(promises) {
        let resultArr = new Array(promises.length)
        let count = 0
        return new Promise((resolve, reject) => {
            promises.forEach((promise, index) => {
                Promise.resolve(promise).then(
                    value => {
                        count++
                        resultArr[index] = value
                        if (count === promises.length) {
                            resolve(resultArr)
                        }
                    },
                    reason => {
                        reject(reason)
                    }
                )
            })
        })
    }

    /**
     * 返回一个Promise, 结果为最先执行完的那个Promise的结果
     * @param {array} promises
     */
    Promise.race = function(promises) {
        return new Promise((resolve, reject) => {
            promises.forEach(promise => {
                Promise.resolve(promise).then(resolve, reject)
            })
        })
    }

    window.Promise = Promise // 向外暴露Promise
 })(window)

参考资料

尚硅谷 Promise 教程(promise 前端进阶必学)

分类:

前端

标签:

前端

作者介绍

麦西的西
V1

公众号:前端成长攻略,学习路线+最新资料