一、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方法中resolve和reject处理方法。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) } } }) }}