Promise及 API 模拟实现

268

Promise的实现首先分为三部分:

  • promise的状态控制
  • promise的后续处理
  • Promise的串联

promise的API分为原型成员(实例成员)和构造函数成员(静态成员)

  • 原型成员

    • then:注册一个后续处理函数,当Promise为resolved状态时运行该函数
    • catch: 注册一个后续处理函数,当Promise为rejected状态时运行该函数
    • finally:[ES2018]注册一个后续处理函数(无参),当Promise为已决时运行该函数
  • 构造函数成员

    • resolve(数据):该方法返回一个resolved状态的Promise,传递的数据作为状态数据,如果传递的数据是Promise,则直接返回传递的Promise对象
    • reject(数据):该方法返回一个rejected状态的Promise,传递的数据作为状态数据
    • all(iterable):这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。
    • race(iterable):当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象

Promise状态控制实现

const MyPromise = (()=>{
    const PENDING = "pending",
          RESOLVED = "resolved",
          REJECTED = "rejected",
          PromiseStatus = Symbol("PromiseStatus"),
          PromiseValue = Symbol("PromiseValue"),
          changeStatus = Symbol("changeStatus");
          
    return class MyPromise{
        /**
         * 改变当前Promise的状态
         * @param {*} newStatus 
         * @param {*} newValue 
         * @param {*} queue 
         */
        [changeStatus](newStatus,newValue){
            if(this[PromiseStatus !==PENDING]){
                return;
            }
            this[PromiseStatus] = newStatus;
            this[PromiseValue] = newValue;
        }      
        
        constructor(executor){
            this[PromiseStatus] = PENDING;
            this[PromiseValue] = undefined;
            const resolve = data =>{
                this[changeStatus](RESOLVED,data)
            }
            const reject = err =>{
                this[changeStatus](REJECTED,err)
            }
            try{
            //实例化一个新的promise对象时会传递一个函数,该函数带有resolve和reject两个形参,并且会自动调用该函数
                executor(resolve,reject);
            }catch(err){
                this[changeStatus](REJECTED,err)
            }
        }
    }
})()

promise状态控制实现: 首先实例化一个promise对象时,需要传递一个函数,该函数带有两个形参resolve,reject, 在实例化过程中会自动调用该函数(executor),执行传递的函数,实例化后得到promise对象带有两个属性,PromiseStatue,promiseValue, 当在该函数的执行体内调用executor的参数时(resolve,reject),会执行构造函数内相应的函数

+Promise的后续处理

const MyPromise = (() => {
    const PENDING = "pending",
        RESOLVED = "resolved",
        REJECTED = "rejected",
        PromiseStatus = Symbol("PromiseStatus"),
        PromiseValue = Symbol("PromiseValue"),
        changeStatus = Symbol("changeStatus"),
        //新增
        thenables = Symbol("thenables"),
        catchables = Symbol("catchables"),
        settleHandler = Symbol('settleHandler')

    return class MyPromise {
        [changeStatus](newStatus, newValue,queue) {
            if (this[PromiseStatus !== PENDING]) {
                return;
            }
            this[PromiseStatus] = newStatus;
            this[PromiseValue] = newValue;
            //执行相应队列中的函数
            queue.forEach(handler =>handler(newValue))
            //这里会执行调用then/catch方法时还未达到已决状态时放入作业队列中的后续处理函数

        }

        constructor(executor) {
            this[PromiseStatus] = PENDING;
            this[PromiseValue] = undefined;
            //新增
            this[thenables] = [];
            this[catchables] = [];
            const resolve = data => {
                //修改
                this[changeStatus](RESOLVED, data,this[thenables])
            }
            const reject = err => {
                //修改
                this[changeStatus](REJECTED, err,this[catchables])
            }
            try {
                //实例化一个新的promise对象时会传递一个函数,该函数带有resolve和reject两个形参,并且会自动调用该函数
                executor(resolve, reject);
            } catch (err) {
                //修改
                this[changeStatus](REJECTED, err,this[catchables])
            }
        }
        
        /**新增
         * promise的后续函数
         * @param {*} handler 后续处理函数
         * @param {*} immediatelyStatus 需要立即执行的状态
         * @param {*} queue 作业队列
         */
        [settleHandler](handler,immediatelyStatus,queue){
            if(this[PromiseStatus] === immediatelyStatus){
                setTimeout(()=>{
                    handler(this[PromiseValue])
                })
            }else{
                queue.push(handler)
            }
        }
        
        /**新增
         * Promise原型上的then方法
         * @param {*} thenable then的处理函数
         * @param {*} catchable catch的处理函数,如果传递了话
         */
        then(thenable, catchable) {
            this[settleHandler](thenable,RESOLVED,this[thenables]);
            this.catch(catchable);//该函数也会执行,但过不了settleHandler状态的一关,自然执行不了catch的后续处理函数
        }

        /**新增
         * Promise原型上的catch方法
         * @param {*} catchable catch的处理函数
         */
        catch(catchable) {
            this[settleHandler](catchable,REJECTED,this[catchables]);
        }
    }
})()

then,catch后续处理: 当调用then/catch方法时,then会接受2个后续处理函数(thenable和catchable),catch会接收一个后续处理函数(catchable) ,如果此时状态处于未决阶段时,会把后续处理函数放入到作业队列里(微队列),等到变成已决阶段时才会从作业队列里按排列顺序(changeStatue中执行)执行作业队列里面的后续处理函数 ,如果此时状态已经处于已决阶段,会直接运行该后续处理函数,如果还是处于未决阶段时(参数数据均来自已决阶段得到的数据)

+Promise的串联

const MyPromise = (() => {
    const PENDING = "pending",
        RESOLVED = "resolved",
        REJECTED = "rejected",
        PromiseStatus = Symbol("PromiseStatus"),
        PromiseValue = Symbol("PromiseValue"),
        changeStatus = Symbol("changeStatus"),
        thenables = Symbol("thenables"),
        catchables = Symbol("catchables"),
        settleHandler = Symbol('settleHandler'),
        linkPromise = Symbol('linkPromise')

    return class MyPromise {
        [changeStatus](newStatus, newValue,queue) {
            if (this[PromiseStatus !== PENDING]) {
                return;
            }
            this[PromiseStatus] = newStatus;
            this[PromiseValue] = newValue;
            //执行相应队列中的函数
            queue.forEach(handler =>handler(newValue))
            //这里会执行调用then/catch方法时还未达到已决状态时放入作业队列中的后续处理函数

        }

        constructor(executor) {
            this[PromiseStatus] = PENDING;
            this[PromiseValue] = undefined;
            this[thenables] = [];
            this[catchables] = [];
            const resolve = data => {
                this[changeStatus](RESOLVED, data,this[thenables])
            }
            const reject = err => {
                this[changeStatus](REJECTED, err,this[catchables])
            }
            try {
                //实例化一个新的promise对象时会传递一个函数,该函数带有resolve和reject两个形参,并且会自动调用该函数
                executor(resolve, reject);
            } catch (err) {
                this[changeStatus](REJECTED, err,this[catchables])
            }
        }
        
        /**
         * promise的后续函数
         * @param {*} handler 后续处理函数
         * @param {*} immediatelyStatus 需要立即执行的状态
         * @param {*} queue 作业队列
         */
        [settleHandler](handler,immediatelyStatus,queue){
            if(typeof handler !== 'function'){
                return;
            }
            if(this[PromiseStatus] === immediatelyStatus){
                setTimeout(()=>{
                    handler(this[PromiseValue])
                })
            }else{
                queue.push(handler)
            }
        }
        
        /**新增
        * promise的串联:then/catch方法被调用后首先调用该函数,生成一个新的Promise对象并返回,
        * 然后then/catch为了要确认自身状态,需要调用settleHandler查看后续处理函数的运行状况,(通过接收运行返回的结果),如果返回的结果是一个可以按照正常逻辑走下去的非promise对象,则then方法返回的新Promise状态为resolved,如果是一个不能按照正常逻辑走下去的非Promise对象,则then方法返回的新Promise状态为rejected,如果返回的是一个promise对象,新promise状态与该Promise状态的then方法返回的后续处理函数执行情况保持一致
        * @param {*} thenalbe //then的后续处理函数
        * @param {*} catchable //catch的后续处理函数
        */
        [linkPromise](thenable, catchable){
            function exec(data,handler,resolve,reject){
                try{
                    const result = handler(data)//得到的result是后续处理函数返回的结果
                    if(result instanceof MyPromise){
                        result.then(d=>{
                            resolve(d)
                        },err=>{
                            reject(err)
                        })
                    }else{
                        resolve(result)
                    }
                }catch(err){
                    reject(err)
                }
            }
            
            return new MyPromise((resolve,reject)=>{
                this[settleHandler](data=>{
                    exec(data,thenable,resolve,reject);
                },RESOLVED,this[thenables])
                this[settleHandler](reason=>{
                    exec(reason,catchable,resolve,reject);
                },REJECTED,this[catchables])
            })
        }
        
        /**修改
         * Promise原型上的then方法
         * @param {*} thenable then的处理函数
         * @param {*} catchable catch的处理函数,如果传递了话
         */
        then(thenable, catchable) {
           return this[linkPromise](thenable,catchable);
        }

        /**修改
         * Promise原型上的catch方法
         * @param {*} catchable catch的处理函数
         */
        catch(catchable) {
           return this[linkPromise](undefined,catchable);
        }
    }
})()

3.串联Promise: 应用场景:当后续的Promise需要用到之前的Promise的处理结果时,需要Promise的串联

promise对象中,无论是then方法还是catch方法,他们都具有返回值,返回的是一个全新的promise对象(return new Promise),该Promise的状态取决于后续处理函数,
如果该后续处理函数还没执行,还在作业队列里,则返回的Promise的状态是挂起状态(pandding),如果该后续处理函数已经在执行,说明该then自身的Promise对象进入了
已决状态(resolve或reject),如果后续处理函数能顺利执行,并返回了值,则then方法创建的全新Promise的状态变为Resolve,(参数数据为then方法return回来的数据)
如果后续处理函数在执行过程中发生了错误,(有报错),则该全新的Promise进入reject状态,(参数数据为报错的数据)

如果前面的Promise的后续处理函数在能顺利执行后,返回的值是一个Promise对象,则返回的新的Promise状态和后续处理返回的Promise状态保持一致,
注意并不是跟返回的Promise的后续处理函数执行状态保持一致(意思就是状态重新配对 return 的promise对象的状态,之前的无效)
(参数来自 已决阶段的后续处理函数返回的参数)

至此,Promsie的功能基本实现。

const MyPromise = (() => {
    const PENDING = "pending",
        RESOLVED = "resolved",
        REJECTED = "rejected",
        PromiseStatus = Symbol("PromiseStatus"),
        PromiseValue = Symbol("PromiseValue"),
        changeStatus = Symbol("changeStatus"),
        thenables = Symbol("thenables"),
        catchables = Symbol("catchables"),
        settleHandler = Symbol('settleHandler'),
        linkPromise = Symbol('linkPromise')

    return class MyPromise {
        [changeStatus](newStatus, newValue,queue) {
            if (this[PromiseStatus !== PENDING]) {
                return;
            }
            this[PromiseStatus] = newStatus;
            this[PromiseValue] = newValue;
            //执行相应队列中的函数
            queue.forEach(handler =>handler(newValue))
            //这里会执行调用then/catch方法时还未达到已决状态时放入作业队列中的后续处理函数

        }

        constructor(executor) {
            this[PromiseStatus] = PENDING;
            this[PromiseValue] = undefined;
            this[thenables] = [];
            this[catchables] = [];
            const resolve = data => {
                this[changeStatus](RESOLVED, data,this[thenables])
            }
            const reject = err => {
                this[changeStatus](REJECTED, err,this[catchables])
            }
            try {
                //实例化一个新的promise对象时会传递一个函数,该函数带有resolve和reject两个形参,并且会自动调用该函数
                executor(resolve, reject);
            } catch (err) {
                this[changeStatus](REJECTED, err,this[catchables])
            }
        }
        
        /**
         * promise的后续函数
         * @param {*} handler 后续处理函数
         * @param {*} immediatelyStatus 需要立即执行的状态
         * @param {*} queue 作业队列
         */
        [settleHandler](handler,immediatelyStatus,queue){
            if(typeof handler !== 'function'){
                return;
            }
            if(this[PromiseStatus] === immediatelyStatus){
                setTimeout(()=>{
                    handler(this[PromiseValue])
                })
            }else{
                queue.push(handler)
            }
        }
        
        /**新增
        * promise的串联:then/catch方法被调用后首先调用该函数,生成一个新的Promise对象并返回,
        * 然后then/catch为了要确认自身状态,需要调用settleHandler查看后续处理函数的运行状况,(通过接收运行返回的结果),如果返回的结果是一个可以按照正常逻辑走下去的非promise对象,则then方法返回的新Promise状态为resolved,如果是一个不能按照正常逻辑走下去的非Promise对象,则then方法返回的新Promise状态为rejected,如果返回的是一个promise对象,新promise状态与该Promise状态的then方法返回的后续处理函数执行情况保持一致
        * @param {*} thenalbe //then的后续处理函数
        * @param {*} catchable //catch的后续处理函数
        */
        [linkPromise](thenable, catchable){
            function exec(data,handler,resolve,reject){
                try{
                    const result = handler(data)//得到的result是后续处理函数返回的结果
                    if(result instanceof MyPromise){
                        result.then(d=>{
                            resolve(d)
                        },err=>{
                            reject(err)
                        })
                    }else{
                        resolve(result)
                    }
                }catch(err){
                    reject(err)
                }
            }
            
            return new MyPromise((resolve,reject)=>{
                this[settleHandler](data=>{
                    exec(data,thenable,resolve,reject);
                },RESOLVED,this[thenables])
                this[settleHandler](reason=>{
                    exec(reason,catchable,resolve,reject);
                },REJECTED,this[catchables])
            })
        }
        
        /**修改
         * Promise原型上的then方法
         * @param {*} thenable then的处理函数
         * @param {*} catchable catch的处理函数,如果传递了话
         */
        then(thenable, catchable) {
           return this[linkPromise](thenable,catchable);
        }

        /**修改
         * Promise原型上的catch方法
         * @param {*} catchable catch的处理函数
         */
        catch(catchable) {
           return this[linkPromise](undefined,catchable);
        }
    }
})()

其他API

  1. Promise.resolve()
static resolve(data){
    if(data instanceof Mypromise){
        return data
    }else{
        return new MyPromise((resolve,reject)=>{
        resolve(data);
        })
    }
}

静态resolve方法,静态resolve方法接受一个参数,如果该参数不是Promise对象,返回一个resolve状态的新Promise 如果该参数是一个promise对象,直接返回该promise对象

  1. Promise.reject()
static reject(reason){
    //写两个参数是因为这这是形参,真正的reject在第二位参数位置
    return new MyPromise((resolve,reject)=>{
        reject(reason)
    })
}

静态reject方法:接收一个参数,返回一个reject状态的Promise对象

  1. Promise.race()
static race(proms){
    return new Promise((resolve,reject)=>{
        proms.forEach(pro=>{
            pro.then(data=>{
                resolve(data);
            },err=>{
                reject(err);
            })
        })
    })
}

静态race方法:接受一个由promise对象组成的数组,返回一个首先到达已决阶段的promise对象

  1. Promise.all()
static all(proms) {
    return new Promise((resolve, reject) => {
        const results = proms.map(p => {
            const obj = {
                result: undefined,
                isResolved: false
            }
            p.then(data => {
                obj.result = data;
                obj.isResolved = true;
                //判断是否所有的全部完成
                const unResolved = results.filter(r => !r.isResolved)
                if (unResolved.length === 0) {
                    //全部完成
                    resolve(results.map(r => r.result));
                }
            }, reason => {
                reject(reason);
            })
            return obj;
        })
    })
}

静态all方法:接受一个由promise对象组成数组,如果全部的Promise的状态都变为resolve,则返回一个resolve状态的Promise,并带上所有promise在resolve后传递的参数组成的数组,如果有一个promise状态报错或变为reject,则变成reject