本文最后更新于:8 个月前
Promise的几种静态方法介绍、适用场景、手写实现
Promise静态方法 Promise静态方法定义在构造函数里
一、resolve() 1.1.介绍 Promise.resolve()
可以把任何值都转换为一个Promise,它只对第一个参数起作用
1 2 3 Promise .resolve (); Promise .resolve (3 ); Promise .resolve (4 ,5 ,6 );
如果传入的参数是一个Promise,那么它相当于空包装(没有变化),因此resolve是一种幂等方法
1 2 3 let p = Promise .resolve (7 ); p === Promise .resolve (p) p === Promise .resolve (Promise .resolve (p))
1.2.模拟实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function myPromise (executor ){ var self = this self.status = 'pending' self.value = undefined self.reason = undefined self.resolvedCallbacks = [] self.rejectedCallbacks = [] function resolve (value ){ if (value instanceof myPromise){ return value.then (resolve, reject) } setTimeout (()=> { if (self.status === 'pending' ){ self.status = 'fulfilled' self.value = value self.resolvedCallbacks .forEach (cb => {cb (self.value )}) } }, 0 ) } ... }
二、reject() 1.介绍 Promise.reject()
会实例化一个拒绝的Promise并抛出一个异步错误(这个错误只能通过reject处理程序捕获 ),reject()
的第一个参数就是拒绝的reason
,它会传给后续的处理程序。
1 2 let p = Promise .reject (3 ); p
reject不是幂等的,传给它一个Promise对象,会被当成它返回的reason
1 2 let p1 = Promise .reject (new Promise (()=> {})); p1
在Promise的执行函数或处理程序中抛出错误会导致拒绝,对应的错误对象会成为拒绝的理由。Promise可以使用任何理由拒绝,但是最好使用统一的Error对象,因为可以捕获错误对象中的栈追踪信息,便于调试。
2.模拟实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function myPromise (executor ){ var self = this self.status = 'pending' self.value = undefined self.reason = undefined self.resolvedCallbacks = [] self.rejectedCallbacks = [] function reject (reason ){ setTimeout (()=> { if (this .status === 'pending' ){ self.status = 'rejected' self.reason = reason self.rejectedCallbacks .forEach ((cb )=> {cb (self.reason )}) } },0 ) } ... }
三、all() 1.介绍 Promise.all()静态方法创建的期约会在一组期约全部解决之后再解决 。
参数: 接受一组Promise实例,如果数组元素不是Promise实例,会自动调用Promise.resolve()
将其转为Promise实例后再处理
返回值: 一个新的Promise实例,PromiseResult是一个数组,包含了参数中所有Promise实例的result,顺序与参数中Promise实例对应
1 2 3 4 5 var all = Promise .all ([ Promise .resolve ('first' ), Promise .resolve ('second' ) ]) all
状态覆盖优先级: rejected > pending > resolved
如果参数中所有Promise实例都resolve了,返回值Promise的状态为resolved,PromiseResult为所有Promise的result按序组成的数组
1 2 3 4 5 var all = Promise .all ([ Promise .resolve ('first' ), Promise .resolve ('second' ) ]) all
如果参数中有rejected的Promise实例,第一个reject的Promise实例的reason作为返回值Promise实例的result(后面reject的reason不记录,但是它们的reject操作一样正常进行)
1 2 3 4 5 6 7 var all = Promise .all ([ Promise .resolve ('first' ), Promise .reject ('second err' ), Promise .resolve ('third' ), Promise .reject ('forth err' ) ]) all
1 2 3 4 5 var all = Promise .all ([ Promise .resolve ('first' ), new Promise (()=> 'init' ) ]) all
2.模拟实现 all()
实现要点:使用闭包保存参数中所有Promise实例的落定结果。如果全部都是resolved
状态,将所有结果保存下来后进行resolve()
返回;如果出现rejected
状态,直接调用(不等结束)reject()
返回。
疑问:如果保证res
闭包数组的结果顺序与参数Promise实例数组的顺序一致?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function myPromise (executor ){ ... function all (iterator ){ if (!Array .isArray (iterator)) return let count = 0 let res = [] return new myPromise ((resolve, reject )=> { for (let item of iterator){ myPromise.resolve (item).then (data => { res[count++] = {status :'fulfilled' , value :data} if (count === iterator.length ) resolve (res) }).catch (e => { reject ({status :'rejected' , reason :e}) }) } }) } }
3.使用场景 通过all()
实现多个异步任务并行执行(eg:并发请求)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 function async_1 ( ){ return new Promise ((resolve, reject )=> { setTimeout (()=> { let data = 'data1' resolve (data) }, 0 ) }) }function async_2 ( ){ return new Promise ((resolve, reject )=> { setTimeout (()=> { let data = 'data2' resolve (data) }, 100 ) }) }let async_works = [async_1 (), async_2 ()] Promise .all (async_works) .then ((result )=> { console .log (result[0 ]) console .log (result[1 ]) }) .catch (err => { console .error (err) })
四、allSettled() 1.介绍 它和Promise.all的区别就是:Promise.all 将在 Promises 数组中的其中一个 Promises 失败后立即失败。而Promise.allSettled 将永远不会失败,一旦数组中的所有 Promises 被完成或失败,它就会完成。
参数 和返回值 与Promise.all一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 var all = Promise .allSettled ([ Promise .resolve ('first' ), Promise .reject ('second err' ), Promise .resolve ('third' ), Promise .reject ('forth err' ) ]) all {status : 'fulfilled' , value : 'first' } {status : 'rejected' , reason : 'second err' } {status : 'fulfilled' , value : 'third' } {status : 'rejected' , reason : 'forth err' }
2.模拟实现 allSettled()
实现要点:使用闭包保存参数数组中所有Promise的结果,不管是resolve还是reject,都保存下来,直到数组中全部元素都落定之后,调用新Promise实例的resolve()
方法将所有结果返回
疑问:如果保证res
数组保存的结果顺序,与参数数组中Promise实例的顺序一致?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function myPromise (executor ){ ... function allSettled (promise_list ){ if (!Array .isArray (iterator)) return let count = 0 let res = [] return new Promise ((resolve, reject )=> { for (let promise of promise_list){ myPromise.resolve (promise) .then (data => res[count++] = {status :'fulfilled' , value : data} ) .catch (err => res[count++]= {status :'rejected' , reason : err}) .finally (()=> { if (count === promise_list.length ) resolve (res) }) } }) } }
五、race() 1.介绍 返回一组集合中最先落定的Promise。不区分resolved还是rejected的Promise实例,只要是第一个“落定”(转换状态)了,Promise.race就包装它并返回。
参数: 接受一组Promise实例,如果不是 Promise 实例,就会调用Promise.resolve()
将参数转为Promise之后再处理
返回值: 一个新的Promise实例,返回值Promise实例的result是参数中第一个resolve的Promise实例的result
1 2 3 4 5 6 7 var race = Promise .race ([ Promise .reject (1 ), Promise .resolve (2 ), Promise .reject (3 ), Promise .resolve (4 ) ]) race
2.模拟实现 race()
的实现要点:只要参数数组中有一个Promise实例落定了,race()
返回的新Promise实例就落定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function myPromise (executor ){ ... function race (promise_list ){ if (!Array .isArray (promise_list)) return return new Promise ((resolve, reject )=> { promise_list.forEach ((promise )=> { Promise .resolve (promise) .then (res => resolve (res)) .catch (err => reject (err)) }) }) } }
3.使用场景 通过race()
设置图片请求超时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function fetchImg (url ){ return new Promise ((resolve,reject )=> { var img = new Image () img.onload = resolve img.onerror = reject img.src = url }) }function timeout ( ){ return new Promise ((resolve,reject )=> { setTimeout (()=> { reject ('请求超时' ) }, 5000 ) }) }Promise .race ([fetchImg (), timeout ()]) .then (result => { console .log (result) }) .catch (err => { console .error (err) })
六、any() 1.介绍 ES2021 引入了Promise.any()
方法 。该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。
2.使用场景 1 2 3 4 5 6 7 8 9 Promise .any ([ fetch (url_1).then (res => res) fetch (url_2).then (res => res) fetch (url_3).then (res => res) ]).then ((first )=> { print (first) }).catch (err => { console .error (err) })
如上例,发送了3个不同url的请求,但实际上请求的是同一个数据。只要其中一个请求成功,any()
返回的实例就会变成fulfilled
。可以用来在不确定url是否可用的情况下,通过发送多个请求来增加请求成功的概率。