Promise基本特性以及优缺点+手写Promise实现(学习记录)

338 阅读5分钟

一、Promise基本特性(then、catch、finally为Promise的原型方法,all、race、resolve、reject、any、allsettled为Promise的静态方法)

  • Promise有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。

  • Promise对象接收一个回调函数作为参数,该回调函数接收两个参数,分别是成功时的回调resolve和失败时的回调reject,另外resolve的参数除了正常值意外,还可能是一个Promise对象的实例,reject的参数通常是一个Error对象的实例。

  • then方法返回一个新的Promise实例,并接收两个参数onResolved(fulfilled状态的回调)和onRejected(rejected状态的回调,该参数可选)。

  • catch方法返回一个新的Promise实例。

  • finally方法不管Promise状态如何都会执行,该方法的回调函数不接受任何参数。

  • Promise.all()方法将多个Promise实例,包装成一个新的Promise实例,该方法接收一个有Promise对象组成的数组作为参数(Promise.all()方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例),参数中只要有一个实例触发catch()方法,都会触发Promise.all()方法返回的新的实例catch方法,如果参数中的某个实力本身调用了catch方法,将不会触发Promise.all()方法返回的新实例的catch()方法。简单来说,Promise.all()方法中传入的Promise实例只要有一个返回的状态为rejected,那这个Promise.all()的结果就是这个失败的实例的结果。只有当全部实例成功,Promise.all()方法产生的Promise实例的返回值才是全部参数实例的返回值集合。

  • Promise.race()方法的参数与Promise.all()方法一样,不同的是,只要参数中的实例有一个率先改变了状态,就会将该实例的状态传给Promise.race()方法,并将返回值作为Promise.race()方法产生的Promise实例的返回值。

  • Promise.resolve()方法将现有对象转为Promise对象(快速产生一个Promise对象),返回一个状态有给定参数决定的Promise对象,如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(参数为空、基本类型或不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该参数传递给对应的then方法,通常来说,如果不知道一个值是否是Promise对象,使用Promise.resolve(value)来返回一个Promise对象,这样就能将value以Promise对象形式使用。

  • Promise.reject(),返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法。

  • Promise.allSettled(),传入的参数和all()方法相同,等所有的Promise实例都已实现状态改变后返回一个状态为fulfilled的Promise对象,它的返回值是一个对象数组,里面是每个Promise实例的结果(状态和返回值)。

  • Promise.any(),传入的参数和all()方法相同,和race()方法不同的是,在any()方法中,只要有一个Promise实例成功,那就返回一个新的Promise对象,这个对象的结果就是成功的Promise实例的结果。

二、Promise的优缺点

优点

  • 统一异步API,Promise将逐渐被用作浏览器的异步API,统一现在各种各样的API,以及不兼容的模式和手法。

  • 和事件相比,Promise更适合处理一次性的结果。在结果计算出来之前或之后都可以注册回调函数,都可以拿到正确的值。Promise这个优点很自然。但是,不能使用Promise处理多次触发的事件。链式处理是Promise的又一个优点,但是事件却不能这样链式处理。

  • 解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。

  • Promise带来的额外好处是包含了更好的错误处理方式(包括了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如Array.prototype.map())

​缺点

  • 无法取消Promise,一旦新建它就会同步执行,无法中途取消。

  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将结束)。

  • Promise真正执行回调的时候,定义Promise那部分实际上已经走完了,所以Promise的报错堆栈上下文不太友好。

三、手写实现Promise

class Promise{    constructor(executor){        this.PromiseState = 'pending';        this.PromiseResult = null;        this.callbacks = [];        let _this = this;        function resolve(data){            if(_this.PromiseState !=='pending')return            _this.PromiseResult = data;            _this.PromiseState ='fulfilled';            // 执行回调函数            setTimeout(()=>{                _this.callbacks.forEach(item=>{                    item.onResolved(data)                })            })               }        function reject(data){            if(_this.PromiseState !=='pending')return            _this.PromiseResult = data;            _this.PromiseState ='rejected';            // 执行回调函数            setTimeout(()=>{                _this.callbacks.forEach(item=>{                    item.onRejected(data)                })            })           }        try{            executor(resolve,reject)        }catch(e){            reject(e)        }    }    // then方法    then(onResolved,onRejected){        let _this = this;        // 省略then方法中resolvereject处理方法。cahch穿透        onResolved = typeof onResolved ==='function'?onResolved:(data)=>{resolve(data)};        onRejected = typeof onRejected ==='function'?onRejected:(e)=>{throw e};        return new Promise((resolve,reject)=>{            function callback(type){                try{                    let result = type(_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:function(){                        setTimeout(()=>{                            callback(onResolved)                        })                    },                    onRejected:function(){                        setTimeout(()=>{                            callback(onRejected)                        })                    }               })            }        })    }    // catch方法    catch(onRejected){        return this.then(undefined,onRejected)    }    // resolve方法    static resolve(param){        return new Promise((resolve,reject)=>{            if(param instanceof Promise){                param.then(v=>{                    resolve(v)                },r=>{                    reject(r)                })            }else{                resolve(param)            }        })    }    // reject方法    static reject(reason){        return new Promise((resolve,reject)=>{            reject(reason)        })    }    // all方法    static all(promises){        return new Promise((resolve,reject)=>{            let count = 0;//计数器,记录当前成功的promise个数            let backArr = [];//成功的promise回调函数存放            for(let i=0;i<promises.length;i++){                promises[i].then(v=>{                    count++;                    backArr[i] = v;                    if(count === promises.length){                        resolve(backArr)                    }                },r=>{                    reject(r)                })                            }        })    }    // race方法    static race(promises){        return new Promise((resolve,reject)=>{            for(let i=0;i<promises.length;i++){                promises[i].then(v=>{                    resolve(v)                },r=>{                    reject(r)                })            }        })    }    // any方法    static any(promises){        return new Promise((resolve,reject)=>{            for(let i=0;i<promises.length;i++){                promises[i].then(v=>{                    resolve(v)                })            }        })    }    // allsettled方法    static allSettled(promises){        return new Promise((resolve,reject)=>{            let count = 0;            let backArr = [];            for(let i=0;i<promises.length;i++){                count++                promises[i].then(v=>{                    backArr[i] = {                        status:"fulfilled",                        value:v                    }                                    },r=>{                    backArr[i] = {                        status:"rejected",                        reason:r                    }                })                if(count === promises.length){                    resolve(backArr)                }            }        })    }}