ITPub博客

首页 > IT职业 > IT生活 > Promise.all中的错误处理

Promise.all中的错误处理

IT生活 作者:websurf 时间:2021-09-09 10:41:45 0 删除 编辑

ID: 符合预期的CoyPan
CoyPan,BAT某厂符合预期的FE,正努力成为一名出色的工程师

写在前面

当我们想“并发执行”若干个任务的时候,我们很容易就想到了Promise.all。但是Promise.all有一个缺陷:当有一个任务失败的时候,就会直接进入catch的逻辑了。这个可能并不是我们想要的结果。想象一下我们同时发出了3个网络请求,其中2个正常返回了,有一个reject了,结果却都挂了,只能被迫进入错误处理的逻辑。我们的需求是:出错的那一个请求不会影响到正常的请求。这种情况应该怎么处理呢?

使用await,增加try…catch…逻辑

要解决上面的问题,思路很简单,只需要再外面再包一层Promise就行了,不管内部的Promise是resolved或者rejected了,外层的Promise都resolve就可以了。这样,Promise.all接收到的,永远都是resolved的Promise。两层的Promise看起来有些别扭,为了代码写起来稍微好看一点,我们用await和try..catch来处理。

/**
 * @param {Promise} p 
 */
async function promiseWithError(p) {
  try {
    const res = await p;
    return {
      err: 0,
      data: res
    };
  } catch(e) {
    return {
      err: 1
    }
  }
}

下面,通过示例代码来看一下。

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise resolve 1');
  }, 1000);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise resolve 2');
  }, 2000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('promise reject 3');
  }, 3000);
});

Promise.all([p1, p2, p3])
  .then(res => {
    console.log('resolve:', res);
  })
  .catch(err => {
    console.log('reject:', err);
  });

// 最终输出为: promise reject 3

我们修改一下代码:

Promise.all([p1, p2, p3].map(item => promiseWithError(item)))
  .then(res => {
    console.log('resolve:', res);
  })
  .catch(err => {
    console.log('reject:', err);
  });

// 最终的输出为:
// resolve: [{ err: 0, data: "promise resolve 1"}, { err: 0, data:"promise resolve 2"}, { err: 1 }]

我们用promiseWithError把原本的promise包了一层。async可以把任何函数都转换为Promise,最终传入Promise.all的依然是一个Promise数组,没有问题。

这样,我们就解决了问题:Promise.all不会因为其中某一个Promsie被reject而导致整个挂掉。

Promise.allSettled

要解决文章开头提到的问题,我们还可以使用Promise.allSettled。

Promise.allSettled()方法返回一个在所有给定的promise已被resolve或被reject后的promise,并带有一个对象数组,每个对象表示对应的promise结果。依然使用上面的例子:

Promise.allSettled([p1, p2, p3])
		.then(res => {
			console.log('resolve:', res);
		})
		.catch(err => {
			console.log('reject:', err);
		});

// 最终输出为:
// resolve: [{ status: "fulfilled", value: "promise resolve 1" }, { status: "fulfilled", value: "promise resolve 2"}, { status: "rejected", reason: "promise reject 3"} ]

目前,Promise.allSettled处于 tc39 stage-4 阶段,马上就会正式发布了。

写在后面

本文阐述了两种处理Promise.all中错误的方法,对日常开发是很有用处的。关于JavaScript中的异步任务相关总结,可以查看我之前的文章:

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1499/viewspace-2825214/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-04-15

  • 博文量
    95
  • 访问量
    1057