一文详解如何有效的处理Promise并发

 更新时间:2023年04月19日 10:17:57   作者:liangyue  
这篇文章主要为大家介绍如何有效的处理Promise并发示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

如上图所示的代码,相信大家在平时的开发中肯定用到不少,我们可以进行优化,使得只用短短一半的时间就可以完成。 在上面的函数中,我们等待用户信息请求完成后再请求详情信息。但这两个函数之间并没有任何关联,所以我们可以同时触发两个请求,并同时等待完成。那么,我们有多少种方式来实现呢?你真的可以处理好Promise的并发么?接下来,我们进入正题。

Promise.all

如何实现

Promise.all 大家应该是比较熟悉的,Promise.all方法接收一个promiseiterable类型,如果所有传入的promise都变成完成状态,Promise.all返回的Promise异步的变为完成。如果传入的promise中有一个失败(rejected),Promise.all将失败的结果给失败状态的回调函数,而不管其他promise是否完成。 我们可以如下实现刚才的代码

async function init() {
  const [user, info] = await Promise.all([
    getUser(),
    getInfo()
  ])
  console.log('init', user, info)
}

现在这种方式,如果我们之前每个请求都需要1秒,一共需要2秒,那么现在两个同时执行只需要1秒就完成了!但是这样也有一个问题:我们并没有考虑报错问题。你可能会认为,这个很简单,把代码放在一个try...cahtch中不就可以了,就像这样:

async function init() {
  try {
    const [user, info] = await Promise.all([
      getUser(),
      getInfo()
    ])
    console.log('init ==== ', user, info)
  } catch(err) {
    console.log('err', err);
  }
}

但是,这样的话会有一个问题,就像这样:

function getUser() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('user reject')
    }, 500);
  })
}
function getInfo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('info reject')
    }, 1000);
  })
}
// 输出 err user reject

由于getUser优先完成并出现错误,此时触发了catch,而当getInfo再次完成并出现错误时,将不会触发catch。因为catch代码已经运行,函数已经完成。 那么,要怎么做呢?接下来,我们就讲讲应该如何处理报错问题。

如何处理报错

解决方式是,给Promise.all中的每个函数加上catch,如下:

function handle(err) {
  console.log('err', err)
}
function onReject(err) {
  handle(err);
  return new Error(err);
}
async function init() {
  const [user, info] = await Promise.all([
    getUser().catch(onReject),
    getInfo().catch(onReject)
  ])
  console.log('init', user instanceof Error, info instanceof Error) // init true true
}

这样,我们在onReject函数中处理错误,并返回这个错误。所以现在我们生成的userinfo要么是Error要么是我们期望的效果,而Error我们可以用instanceof检查它。

Promise.allSettled

解决并发我们还可以使用 Promise.allSettled ,我们会得到一个包含每个Promise结果的值或错误信息。

如何实现

接下来,我们来使用一下,代码如下:

async function init() {
  const [userStatus, infoStatus] = await Promise.allSettled([
    getUser(),
    getInfo()
  ])
  console.log('info', userStatus, infoStatus)
}

现在,我们可以得到这样的数据:

结果对象有3个属性:

  • status: fulfilledrejected
  • value: 仅在statusfulfilled时出现,为Promiseresolve返回的值
  • reason: 仅在statusrejected时出现,为Promisereject时返回的值

因此,我们可以读取到每个Promise的状态,并单独处理每个错误而不会遗漏任何的信息。

最后两个技巧

Promise.race

Promise.race方法可接受一个可迭代的promise返回一个promise,一旦迭代器中某个promise解决或拒绝,返回的promise就会resolvereject

我们可以这样实现一个简单的超时功能,代码如下:

function getUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('user resolve')
    }, 5100);
  })
}
async function init() {
  // Race to see which Promise completes first
  const racePromise = Promise.race([
    getUser(),
    new Promise((resolve, reject) =>
      // Time out after 5 seconds
      setTimeout(() => reject(new Error('Timeout')), 5000)
    )
  ])
  try {
    const result = await racePromise
    console.log('result', result)
  } catch (err) {
    console.log('err', err)
    // Timed out!
  }
}

注意,通常情况下,如果有超时,那么你需要尽量的取消未完成的待处理任务。

另外,最好还是处理所有promisereject

const racePromise = Promise.race([
    getUser().catch(onReject),
    // xxx
  ])

Promise.any

Promise.any 等待任何一个promise成功则为成功,只有全部的promise都被reject,才会返回reject。通常我们可以使用Promise.any来实现,当一个promise先完成后,取消其他的promise,不过要注意的是,我们并不总是同时要处理多个数据,只是因为我们可以做到,所以要谨慎的使用它。

通常,我们不想出现未被处理的reject,所以,我们应该这样写:

const anyPromise = Promise.any([
    getUser().catch(onReject),
    getInfo().catch(onReject)
])

总结

前面我们已经介绍了在使用promise处理并发问题时,应该如何的处理promisereject。但是也需要注意:过度的并发会导致网络抖动、磁盘抖动或其他问题,虽然可以,但并不是一定要这样做,有时使用async await也可以使代码更容易理解和维护,所以,在使用之前我们更需要考虑是否需要。

以上就是一文详解如何有效的处理Promise并发的详细内容,更多关于有效处理Promise并发的资料请关注脚本之家其它相关文章!

相关文章

  • 『JavaScript』限制Input只能输入数字实现思路及代码

    『JavaScript』限制Input只能输入数字实现思路及代码

    一个文字方块必须限制只能输入数字(或是小数点)并且要支援 IE 和 Firefox,接下来为大家介绍下如何解决这个需求
    2013-04-04
  • JavaScript算法面试题

    JavaScript算法面试题

    这篇文章主要给大家分享的是JavaScript算法面试题汇总,文章举例清晰内容详细,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-04-04
  • 微信小程序自定义导航栏效果

    微信小程序自定义导航栏效果

    这篇文章主要为大家详细介绍了微信小程序自定义导航栏效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • js利用iframe实现选项卡效果

    js利用iframe实现选项卡效果

    这篇文章主要为大家详细介绍了js利用iframe实现选项卡效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • 详解js实现线段交点的三种算法

    详解js实现线段交点的三种算法

    下面小编就最近学会的一些”求线段交点”的算法说一说, 希望对大家有所帮助。“求线段交点”是一种非常基础的几何计算, 在很多游戏中都会被使用到。有需要的可以参考学习
    2016-08-08
  • JavaScript仿京东搜索框实例

    JavaScript仿京东搜索框实例

    这篇文章主要为大家详细介绍了JavaScript仿京东搜索框实例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • JavaScript 引用类型实例详解【数组、对象、严格模式等】

    JavaScript 引用类型实例详解【数组、对象、严格模式等】

    这篇文章主要介绍了JavaScript 引用类型,结合实例形式详细分析了JavaScript 数组、对象、严格模式引用类型相关概念、原理及操作注意事项,需要的朋友可以参考下
    2020-05-05
  • Div自动滚动到末尾的代码

    Div自动滚动到末尾的代码

    非常不错的思路,自动滚动到div末尾
    2008-10-10
  • Js中foreach()用法及使用的坑记录

    Js中foreach()用法及使用的坑记录

    这篇文章主要介绍了Js中foreach()用法及使用的坑记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • JS如何实现网站中PC端和手机端自动识别并跳转对应的代码

    JS如何实现网站中PC端和手机端自动识别并跳转对应的代码

    这篇文章主要介绍了JS如何实现网站中PC端和手机端自动识别并跳转对应的代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01

最新评论