1.了解Promise

众所周知,Promise是JS中异步编程的一种解决方案。
在模拟实现Promise之前,首先需要了解Promise的特性。

1.一个promise(Promise的实例),有三种状态,初始时的等待态pending,成功时的成功态resolved以及失败态rejected。promise的状态只能被改变一次,只能从pending成为resolved或者rejected,改变不可逆。
2.promise改变状态的方式有三种,当调用resolve时,由pending变为resolved,当调用reject,或者执行器函数内部抛出异常时,由pending变为rejected。
3.对同一个promise指定了多个回调函数时,当promise变为对应状态时,对应的回调函数全部都会执行。
4.p.then() 返回的Promise的结果状态怎么确定?
由then指定的回调函数的结果决定
①如果抛出异常,新的promise变成rejected
②如果回调函数返回的是不是Promise的任意值string,undefined等等,新的promise变为fulfilled,数据是返回的值
③如果回调函数返回的是一个promise对象。返回值promise对象的结果和状态就是新的promise的结果和状态
5.promise异常穿透:在之前的then中只写了一个成功的回调,没有写失败的回调 相当于隐式的写了 err=>{throw err} 所以会穿透
①当使用promise的then链式调用时,可以在最后指定失败的回调
②前面的任何操作出现了异常都会传到最后的失败的回调函数中处理
6.中断promise链:当使用promise链式调用时,在中间中断,不再调用后面的回调函数
方法:在需要中断处 返回一个pending状态的promise return new Promise(()={})

2.Promise的模拟实现

实现Promise中的then、catch、all、race、resolve、reject方法。
使用的时ES6语法。

1.MyPromise整体结构

class MyPromise {    //构造函数 参数是执行器函数    constructor(executor) {           }    //指定成功和失败的回调函数,返回一个新的promise    then(resolvedCallBack, rejectedCallBack = error => { throw error }) {    }    //返回一个新的promise    catch(rejectedCallBack) {    }    /**     * @author: forceddd     * @desc: 要判断传入的数组是否全部是promise对象     * @param ArrayOfPromises     * @return: 返回最先完成的promise任务结果和状态 无论成功或者失败     */    static race(promises) {    }    /**     * @author: forceddd     * @desc: 当所有promise都成功时,返回一个成功态的promise 数据是所有promise成功数据组成的数组 否则返回一个失败态的promise     * @param ArrayOfPromises     * @return: promise     */    static all(promises) {           }    /**     * @author: forceddd     * @desc: 传入非promise 返回一个成功态的promise data是该参数     * 传入promise 返回值的状态和结果由参数promise的状态和结果决定     * @param any      * @return: 返回一个指定结果的promise     */    static resolve(data) {    }    /**     * @author: forceddd     * @desc: 不考虑传入promise     * @param reason      * @return: 返回一个失败状态的promise 失败原因是传入的参数      */    static reject(error) {    }}

2.构造器的实现

//构造函数 参数是执行器函数(执行器函数是同步执行的)    constructor(executor) {        this.status = 'pending';//当前实例的状态        this.data = undefined;//用于存储完成后的数据        this.callBacks = [];//用于存储promise完成之前,即状态仍为pending时,便指定的回调函数  [{resolveCb,rejectCb}]         //箭头函数让this指向构造函数中的this 即实例 否则resolve和reject中的this会指向window        //声明两个用于改变promise状态的函数,并且要作为参数传入执行器函数executor中        const resolve = data => {            //status只能被修改一次 判断当前是否是初始值pending            if (this.status !== 'pending') return;            //改变promise状态为成功态            this.status = 'resolved';            //存储成功值            this.data = data;            //如果此时有的回调函数已经被指定了 应当立即--异步地--执行这些回调函数            //通过setTimeout将成功地回调函数放入异步队列            if (this.callBacks.length) {                setTimeout(() => {                    this.callBacks.forEach(cbObj => cbObj.resolvedCallBack(data))                })            }        }        const reject = error => {            //status只能被修改一次 判断当前是否是初始值pending            if (this.status !== 'pending') return;            //改变promise状态为失败态            this.status = 'rejected';            //存储失败信息            this.data = error;            //如果此时有的回调函数已经被指定了 应当立即--异步--执行这些回调函数            //通过setTimeout将失败地回调函数放入异步队列            if (this.callBacks.length) {                setTimeout(() => {                    this.callBacks.forEach(cbObj => cbObj.rejectedCallBack(error))                })            }        }        // 同步执行executor try catch用于捕获executor抛出的异常        try {            executor(resolve, reject)        } catch (error) {            //如果抛出了异常,promise要变为rejected            reject(error)        }    }

3.then的实现

//指定成功和失败的回调函数,返回一个新的promise    //给rejectedCallBack默认值 实现异常穿透处理 即不传入rejectedCallBack,    //但又是失败态时,会执行默认函数,抛出异常,将then返回值promise转为失败态    then(resolvedCallBack, rejectedCallBack = error => { throw error }) {        //因为在catch中 resolvedCallBack我会传入一个null 所以此处增加一个判断条件        resolvedCallBack = typeof resolvedCallBack === 'function' ? resolvedCallBack : _ => _;        //then的返回值是一个promise        return new MyPromise((resolve, reject) => {            /**             * @desc: 处理then的返回值              *  1.如果执行回调函数时抛出了异常 返回一个失败的promise error是异常信息                2.如果回调函数返回值不是promise对象 ,返回一个成功的promise data是回调函数返回值                3.如果回调函数的返回值是一个promise  这个promise的状态和结果作为返回值promise的状态和结果                              * @param: cb             * @return:              */            const handleReturn = cb => {                let res;//接收成功或者失败的回调函数的返回值                try {                    res = cb(this.data);                    res instanceof MyPromise                        //3.如果回调函数的返回值是一个promise  这个promise的状态和结果作为返回值promise的状态和结果                        ? res.then(                            data => resolve(data),                            error => reject(error)                        )                        //简写形式 成功时 将resolve作为回调函数resolvedCallBack传入 内部会执行 resolvedCallBack(this.data),                        //和传入一个data => resolve(data)效果相同                        // res.then(resolve, reject)                        //2.如果回调函数返回值不是promise对象 ,返回一个成功的promise data是回调函数返回值                        : resolve(res)                } catch (error) {                    //1.如果执行回调函数时抛出了异常 返回一个失败的promise error是异常信息                     reject(error)                }            }            if (this.status === 'pending') {                //此时实例仍然时pending态 回调函数已经被声明了 将指定的回调函数存储到callBacks中                //此时同样要根据回调函数返回值来判断then的返回值 所以不能直接像下面一样存储回调函数,需要外包一层函数,以便对返回值进行判断                // this.callBacks.push({ resolvedCallBack, rejectedCallBack })                this.callBacks.push({                    resolvedCallBack: _ => handleReturn(resolvedCallBack),                    rejectedCallBack: _ => handleReturn(rejectedCallBack)                })                /* 在状态改变之后 指定的回调函数 会立即--异步--执行 */            } else if (this.status === 'resolved') {                setTimeout(() => handleReturn(resolvedCallBack));            } else {                setTimeout(() => handleReturn(rejectedCallBack));            }        })    }

4.catch的实现

    //返回一个新的promise catch是then的一个语法糖    catch(rejectedCallBack) {        return this.then(null, rejectedCallBack)    }

5.resolve和reject的实现

/**     * @author: forceddd     * @desc: 传入非promise 返回一个成功态的promise data是该参数     * 传入promise 返回值的状态和结果由参数promise的状态和结果决定     * @param any      * @return: 返回一个指定结果的promise     */static resolve(data) {        return new MyPromise((resolve, reject) => {            data instanceof MyPromise                ?                 /*res.then(                       data => resolve(data),                       error => reject(error)                        )                    的简写    */                data.then(resolve, reject)                : resolve(data)        })    }    /**     * @author: forceddd     * @desc: 不考虑传入promise     * @param reason      * @return: 返回一个失败状态的promise 失败原因是传入的参数      */    static reject(error) {        return new MyPromise((_, reject) => reject(error))    }

6.race的实现

/**     * @author: forceddd     * @desc: 要判断传入的数组是否全部是promise对象     * @param ArrayOfPromises     * @return: 返回最先完成的promise任务结果 无论成功或者失败     */    static race(promises) {        //返回一个promise        return new MyPromise((resolve, reject) => {            promises.forEach(promise => {                //判断元素是不是promise 如果不是,通过resolve函数转换成promise                promise = promise instanceof MyPromise ? promise : MyPromise.resolve(promise);                //将最先完成的promise状态和结果 作为race返回值的状态和结果                 promise.then(resolve, reject)            })        })    }

7.all的实现

 /**     * @author: forceddd     * @desc: 当所有promise都成功时,返回一个成功态的promise 数据是所有promise成功数据组成的数组 否则返回一个失败态的promise     * @param ArrayOfPromises     * @return: promise     */    static all(promises) {        let resolveCount = 0;//记录执行then中成功回调函数的次数 每执行一次then的回调函数说明有个一个promise已经有了结果        const results = new Array(promises.length)//创建一个长度和promises相同的数组,用来存储成功的data        return new MyPromise((resolve, reject) => {            promises.forEach((promise, index) => {                //将不是promise的元素转换成promise                promise = promise instanceof MyPromise ? promise : MyPromise.resolve(promise);                promise.then(                    data => {                        results[index] = data;                        resolveCount++                        resolveCount === promises.length ? resolve(results) : null                    },                    error => reject(error) //将all的返回值变为reject状态                 )            })        })    }