文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何实现Promise.all

2023-07-02 08:59

关注

这篇文章主要介绍“如何实现Promise.all”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“如何实现Promise.all”文章能帮助大家解决问题。

Promise.resolve

简要回顾

这是MDN上的解释,我们挨个看一下

小例子

// 1. 非Promise对象,非thenable对象Promise.resolve(1).then(console.log) // 1// 2. Promise对象成功状态const p2 = new Promise((resolve) => resolve(2))Promise.resolve(p2).then(console.log) // 2// 3. Promise对象失败状态const p3 = new Promise((_, reject) => reject('err3'))Promise.resolve(p3).catch(console.error) // err3// 4. thenable对象const p4 = {  then (resolve) {    setTimeout(() => resolve(4), 1000)  }}Promise.resolve(p4).then(console.log) // 4// 5. 啥都没传Promise.resolve().then(console.log) // undefined

源码实现

Promise.myResolve = function (value) {  // 是Promise实例,直接返回即可  if (value && typeof value === 'object' && (value instanceof Promise)) {    return value  }  // 否则其他情况一律再通过Promise包装一下   return new Promise((resolve) => {    resolve(value)  })}// 测试一下,还是用刚才的例子// 1. 非Promise对象,非thenable对象Promise.myResolve(1).then(console.log) // 1// 2. Promise对象成功状态const p2 = new Promise((resolve) => resolve(2))Promise.myResolve(p2).then(console.log) // 2// 3. Promise对象失败状态const p3 = new Promise((_, reject) => reject('err3'))Promise.myResolve(p3).catch(console.error) // err3// 4. thenable对象const p4 = {  then (resolve) {    setTimeout(() => resolve(4), 1000)  }}Promise.myResolve(p4).then(console.log) // 4// 5. 啥都没传Promise.myResolve().then(console.log) // undefined

疑问

从源码实现中,并没有看到对于thenable对象的特殊处理呀!其实确实也不需要在Promise.resolve中处理,真实处理的地方应该是在Promise构造函数中,如果你对这块感兴趣,马上就会写Promise的实现篇,期待你的阅读噢。

Promise.reject

简要回顾

Promise.reject() 方法返回一个带有拒绝原因的Promise对象。

Promise.reject(new Error('fail'))  .then(() => console.log('Resolved'),         (err) => console.log('Rejected', err))// 输出以下内容        // Rejected Error: fail//    at <anonymous>:2:16

源码实现

reject实现相对简单,只要返回一个新的Promise,并且将结果状态设置为拒绝就可以

Promise.myReject = function (value) {  return new Promise((_, reject) => {    reject(value)  })}// 测试一下Promise.myReject(new Error('fail'))  .then(() => console.log('Resolved'),         (err) => console.log('Rejected', err))// Rejected Error: fail//    at <anonymous>:9:18

Promise.all

简要回顾

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。这个静态方法应该是面试中最常见的啦

const p = Promise.all([p1, p2, p3])

最终p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

const p1 = Promise.resolve(1)const p2 = new Promise((resolve) => {  setTimeout(() => resolve(2), 1000)})const p3 = new Promise((resolve) => {  setTimeout(() => resolve(3), 3000)})const p4 = Promise.reject('err4')const p5 = Promise.reject('err5')// 1. 所有的Promise都成功了const p11 = Promise.all([ p1, p2, p3 ]).then(console.log) // [ 1, 2, 3 ]      .catch(console.log)// 2. 有一个Promise失败了const p12 = Promise.all([ p1, p2, p4 ]).then(console.log)      .catch(console.log) // err4// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值const p13 = Promise.all([ p1, p4, p5 ]).then(console.log)      .catch(console.log) // err4

源码实现

Promise.myAll = (promises) => {  return new Promise((rs, rj) => {    // 计数器    let count = 0    // 存放结果    let result = []    const len = promises.length    if (len === 0) {      return rs([])    }    promises.forEach((p, i) => {      // 注意有的数组项有可能不是Promise,需要手动转化一下      Promise.resolve(p).then((res) => {        count += 1        // 收集每个Promise的返回值         result[ i ] = res        // 当所有的Promise都成功了,那么将返回的Promise结果设置为result        if (count === len) {          rs(result)        }        // 监听数组项中的Promise catch只要有一个失败,那么我们自己返回的Promise也会失败      }).catch(rj)    })  })}// 测试一下const p1 = Promise.resolve(1)const p2 = new Promise((resolve) => {  setTimeout(() => resolve(2), 1000)})const p3 = new Promise((resolve) => {  setTimeout(() => resolve(3), 3000)})const p4 = Promise.reject('err4')const p5 = Promise.reject('err5')// 1. 所有的Promise都成功了const p11 = Promise.myAll([ p1, p2, p3 ]).then(console.log) // [ 1, 2, 3 ]      .catch(console.log)// 2. 有一个Promise失败了const p12 = Promise.myAll([ p1, p2, p4 ]).then(console.log)      .catch(console.log) // err4// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值const p13 = Promise.myAll([ p1, p4, p5 ]).then(console.log)      .catch(console.log) // err4// 与原生的Promise.all返回是一致的

Promise.allSettled

简要回顾

有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。显然Promise.all(其只要是一个失败了,结果即进入失败状态)不太适合,所以有了Promise.allSettled

Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更,一旦发生状态变更,状态总是fulfilled,不会变成rejected

还是以上面的例子为例, 我们看看与Promise.all有什么不同

const p1 = Promise.resolve(1)const p2 = new Promise((resolve) => {  setTimeout(() => resolve(2), 1000)})const p3 = new Promise((resolve) => {  setTimeout(() => resolve(3), 3000)})const p4 = Promise.reject('err4')const p5 = Promise.reject('err5')// 1. 所有的Promise都成功了const p11 = Promise.allSettled([ p1, p2, p3 ]).then((res) => console.log(JSON.stringify(res, null,  2)))// 输出 // 2. 有一个Promise失败了const p12 = Promise.allSettled([ p1, p2, p4 ]).then((res) => console.log(JSON.stringify(res, null,  2)))// 输出 // 3. 有两个Promise失败了const p13 = Promise.allSettled([ p1, p4, p5 ]).then((res) => console.log(JSON.stringify(res, null,  2)))// 输出 

可以看到:

源码实现

Promise.myAllSettled = (promises) => {  return new Promise((rs, rj) => {    let count = 0    let result = []    const len = promises.length    // 数组是空的话,直接返回空数据    if (len === 0) {      return rs([])    }    promises.forEach((p, i) => {      Promise.resolve(p).then((res) => {        count += 1        // 成功属性设置         result[ i ] = {          status: 'fulfilled',          value: res        }        if (count === len) {          rs(result)        }      }).catch((err) => {        count += 1        // 失败属性设置         result[i] = {           status: 'rejected',           reason: err         }        if (count === len) {          rs(result)        }      })    })  })}// 测试一下const p1 = Promise.resolve(1)const p2 = new Promise((resolve) => {  setTimeout(() => resolve(2), 1000)})const p3 = new Promise((resolve) => {  setTimeout(() => resolve(3), 3000)})const p4 = Promise.reject('err4')const p5 = Promise.reject('err5')// 1. 所有的Promise都成功了const p11 = Promise.myAllSettled([ p1, p2, p3 ]).then((res) => console.log(JSON.stringify(res, null,  2)))// 输出 // 2. 有一个Promise失败了const p12 = Promise.myAllSettled([ p1, p2, p4 ]).then((res) => console.log(JSON.stringify(res, null,  2)))// 输出 // 3. 有两个Promise失败了const p13 = Promise.myAllSettled([ p1, p4, p5 ]).then((res) => console.log(JSON.stringify(res, null,  2)))// 输出 

Promise.race

简单回顾

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3])

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

const p1 = new Promise((resolve, reject) => {  setTimeout(resolve, 500, 1)})const p2 = new Promise((resolve, reject) => {  setTimeout(resolve, 100, 2)})Promise.race([p1, p2]).then((value) => {  console.log(value) // 2})Promise.race([p1, p2, 3]).then((value) => {  console.log(value) // 3})

源码实现

聪明的你一定马上知道该怎么实现了,只要了解哪个实例先改变了,那么Promise.race就跟随这个结果,那么就可以写出以下代码

Promise.myRace = (promises) => {  return new Promise((rs, rj) => {    promises.forEach((p) => {      // 对p进行一次包装,防止非Promise对象      // 并且对齐进行监听,将我们自己返回的Promise的resolve,reject传递给p,哪个先改变状态,我们返回的Promise也将会是什么状态      Promise.resolve(p).then(rs).catch(rj)    })  })}// 测试一下const p1 = new Promise((resolve, reject) => {  setTimeout(resolve, 500, 1)})const p2 = new Promise((resolve, reject) => {  setTimeout(resolve, 100, 2)})Promise.myRace([p1, p2]).then((value) => {  console.log(value) // 2})Promise.myRace([p1, p2, 3]).then((value) => {  console.log(value) // 3})

关于“如何实现Promise.all”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯