温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么有效的处理Promise并发

发布时间:2023-04-19 15:54:14 来源:亿速云 阅读:124 作者:iii 栏目:开发技术

本文小编为大家详细介绍“怎么有效的处理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)
    }

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

    怎么有效的处理Promise并发

    结果对象有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并发”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI