You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constmyPromise=require('./promiseOtherAPI')myPromise.reject(newError('fail')).then(function(){// not called},function(error){console.error(error);// Error: fail});
constmyPromise=require('./promiseOtherAPI')varp1=newmyPromise(function(resolve,reject){resolve('Success');});p1.then(function(value){console.log(value);// "Success!"throw'oh, no!';}).catch(function(e){console.log(e);// "oh, no!"}).then(function(){console.log('after a catch the chain is restored');},function(){console.log('Not fired due to the catch');});// 以下行为与上述相同p1.then(function(value){console.log(value);// "Success!"returnPromise.reject('oh, no!');}).catch(function(e){console.log(e);// "oh, no!"}).then(function(){console.log('after a catch the chain is restored');},function(){console.log('Not fired due to the catch');});// 捕获异常constp2=newmyPromise(function(resolve,reject){thrownewError('test');});p2.catch(function(error){console.log(error);});// Error: test
promise.all实现,我发现入参数组元素是含有 then 属性的对象或者函数,不会原样返回;我觉得不用判断是否是 promise 的实例了,myPromise.resolve 的处理就可以了
我按照所给的用例跑了一下,测试代码如下:
constmyPromsie=require('../myPromiseFully')constp1=Promise.resolve(3);constp2={then: function(onFulfill){onFulfill('then函数')}}constp3=42;Promise.all([p1,p2,p3]).then(result=>{console.log('原生 all fulfilled :>> ',result);},reason=>{console.log('原生 all rejected :>> ',reason)})myPromsie.all([p1,p2,p3]).then(result=>{console.log('手写 all fulfilled :>> ',result);},reason=>{console.log('手写 all rejected :>> ',reason)})
本系列的主题是 JavaScript 深入系列,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末。
如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。
前言
我们在上篇用了很大功夫实现了 Promise 的核心方法,并且通过了 Promises/A+ 官方872个测试用例测试,接下来实现这些静态方法已经是小菜一碟了,因为这些 API 全部是对前面的封装而已。
上篇文章在这里:JavaScript 深入系列之 Promise 核心原理的模拟实现,通过 Promises/A+ 官方872个测试用例
官方 Promise 还有很多API ,除了 then 方法以外还有 两个实例方法:
◾ 以及目前 Promise 规范的 六个静态方法:
虽然这些都不在 Promise/A+ 规范里面,但是我们也来实现一下吧,加深理解。其实我们前面我们用了很大功夫实现了 Promise/A+ ,现在再来实现这些已经是小菜一碟了,因为这些API全部是前面的封装而已。
1. 实现 Promise.resolve
Promise.resolve(value) 将给定的一个值转为Promise对象。
"then"
方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;resolve()
方法 (状态为fulfilled)。根据规范我们这样实现(写法一):
使用官方例子测试一下:
输出结果:
测试通过 ✌
静态方法改造
类(class)通过 static 关键字定义静态方法。不能在类的实例上调用静态方法,而应该通过类本身调用。这些通常是实用程序方法,例如创建或克隆对象的功能。
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
写法二、使用静态方法 static:
2. 实现 Promise.reject
Promise.reject()
方法返回一个带有拒绝原因的Promise
对象。官方例子:
输出结果:
根据规范我们这样实现(写法一):
使用官方用例测试一下:
输出结果:
Error: fail
测试通过 ✌
写法二、使用静态方法 static:
3. 实现 Promise.prototype.catch
catch()
方法返回一个Promise
,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected)
相同。事实上, calling
obj.catch(onRejected)
内部callsobj.then(undefined, onRejected)
。(这句话的意思是,我们显式使用obj.catch(onRejected)
,内部实际调用的是obj.then(undefined, onRejected)
)Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。因此我们可以这样来实现:
就一行代码,我的天,居然这么简单😱
我们用官方例子来测试一下吧
输出:
测试通过,没毛病😏
4. 实现 Promise.prototype.finally
finally()
方法返回一个Promise
。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise
是否成功完成后都需要执行的代码提供了一种方式。这避免了同样的语句需要在
then()
和catch()
中各写一次的情况。该方法是 ES2018 引入标准的。由于无法知道promise的最终状态,所以
finally
的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。根据规范我们这样实现:
对,就这么简单 ✌
测试一下:
输出结果:
测试通过 👏👏👏
5. 实现 Promise.all
Promise.all()
方法接收一个promise
的iterable
类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise
实例, 输入的所有promise
的resolve
回调的结果是一个数组。Promise.all
等待所有都完成(或第一个失败)(也就是如果参数里的某值不是Promise,则需要原样返回在数组里)
根据规范我们这样实现:
使用官方例子测试一下:
输出结果:
测试通过 👏👏👏
测试 Promise.all 的快速返回失败行为
Promise.all 在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,有一个立即调用失败函数,那么 Promise.all 将立即变为失败。
输出结果:
测试通过 👏👏👏
2021年12月30日 更新
Byron_Yan 同学 在2021年12月30日留言:
我按照所给的用例跑了一下,测试代码如下:
经测试确实存在上述问题,我们修改一下逻辑:
再执行一下前面的测试用例:
测试通过✌
下面我们对上面代码做一下优化
对thenable对象的处理其实借鉴了
myPromise.resolve()
的实现:而我们
Promise.all
方法的又恰恰用到了myPromise.resolve()
,所以这样的写法其实很多余:这里直接用
myPromsie.resolve
才是最优解(至少现在我认为是)Promsie.all
最终版的实现如下:该写法通过了测试👏👏👏:
感谢Byron_Yan 同学的留言 👍👍👍
6. 实现 Promise.allSettled
Promise.allSettled(iterable)方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
当你有多个彼此不依赖的异步任务成功完成时,或者你总是想知道每个promise的结果时,通常使用它。
相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束。
参数 iterable 是一个可迭代的对象,例如Array,其中每个成员都是Promise。
对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。
在实现前我们需要验证一点,输入的非promise值应该怎么处理?
为此我们在
Promise.allSettled(iterable)
的参数 iterable 中传入一个非promise值,看一下 Promise.allSettled() 方法内部会怎么处理:输出结果:
我们发现 Promise.allSettled() 方法内部将非 Promise 值转换成 Promise 了
那下面我们就将非 Promise 值通过 Promise.resolve 转换为 Promise 进行统一处理
根据规范我们这样实现:
使用官方例子测试一下:
输出结果:
测试通过 perfect ✌✌✌
7. 实现 Promise.any
本质上,这个方法和Promise.all()是相反的。
Promise.any()
接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和
AggregateError
类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。(即将非Promise值,转换为Promise并当做成功)
(如果所有Promise都失败,则报错)
在
node v14.15.4
版本下测试Promise.any()
发现还没有被支持:Uncaught TypeError: Promise.any is not a function
既然是处于草案阶段的实验性 API ,如果想要在各版本浏览器中兼容性使用,那实现
Promise.any()
就很有必要 💪根据规范我们这样实现:
使用官方例子测试一下:
发现报错了,提示 AggregateErro 没有定义,这里不是我们代码的问题,是因为这个 AggregateErro ,
node v14.15.4
版本没有支持,按理说这个版本已经很高了,为什么还没有支持呢?和 Promise.any() 一样,这个 AggregateError 也是一个实验中的功能,处于Stage 3 Draft (第三阶段草案):
我们通过升级 node 版本来兼容这些处于草案阶段的实验功能~
从
node v14.15.4
升级到最新的node v16.13.0
再次验证即可通过:
用其他用例测试一下该方法:
输出结果:
测试通过 😊
8. 实现 Promise.race()
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的返回值,从而异步地解析或拒绝(一旦堆栈为空)。
race
函数返回一个Promise
,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。如果传的迭代是空的,则返回的 promise 将永远等待。
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
根据规范我们这样实现:
最后测试一下代码:
输出结果为:
测试通过 🎉🎉🎉
完整代码
手写 Promise 全部方法的完整版代码较长,这里如果看不清楚的可以去我的GitHub上看:
或者
❤️ 结尾
更多更全更详细 的 优质内容, 猛戳这里查看
参考
查看原文
查看全部文章
博文系列目录
交流
各系列文章汇总:https://github.com/yuanyuanbyte/Blog
我是圆圆,一名深耕于前端开发的攻城狮。
The text was updated successfully, but these errors were encountered: