Promise.allSettled
⭐️ ES2020(ES11)新特性
Promise.allSettled 方法返回一个在所有给定的 Promise 都已经 fullfilled 或 rejected 后的 Promise,并带有一个对象数组,每个对象表示对应的 Promise 结果。
当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个 Promise 的结果时,通常使用它。
语法
语法:
Promise.allSettled(iterable);
类型声明:
interface PromiseFulfilledResult<T> {
  status: 'fulfilled';
  value: T;
}
interface PromiseRejectedResult {
  status: 'rejected';
  reason: any;
}
type PromiseSettledResult<T> = PromiseFulfilledResult<T> | PromiseRejectedResult;
interface PromiseConstructor {
  allSettled<T extends readonly unknown[] | readonly [unknown]>(
    values: T
  ): Promise<
    { -readonly [P in keyof T]: PromiseSettledResult<T[P] extends PromiseLike<infer U> ? U : T[P]> }
  >;
  allSettled<T>(
    values: Iterable<T>
  ): Promise<PromiseSettledResult<T extends PromiseLike<infer U> ? U : T>[]>;
}
参数说明:
| 参数 | 说明 | 类型 | 
|---|---|---|
| iterable | 见下方 | any | 
根据传入参数的不同,会有不同的响应效果:
- 空的具备 Iterator 接口的对象,返回状态为 Fulfilled 的 Promise
- 不包含任何 Promise,返回异步完成的 Promise
- 其他情况,返回状态为 Pending 的 Promise
<br />
- 参数 iterable必须具备 Iterator 接口,且每个成员都是 Promise 实例
- 如果 iterable内每个成员都不是 Promise 实例,会先调用 Promise.resolve 将每个成员转化为 Promise 实例,再进一步处理
方法描述
对于 Promise.allSettled 执行集合中的每个 Promise 都已经完成后,无论时成功(fulfiiled)或是拒绝(rejected),未决议的 Promise 将被异步完成。那时,所返回的 Promise 的处理器将传入一个数组作为输入,该数组包含原始 Promise 集合中每个 Promise 的结果。
对于每个结果对象,都有一个 status 字段。
- 如果值为 fulfilled,则结果对象上存在一个value
- 如果值为 rejected,则存在一个reason
value 和 reason 分别反映了每个 Promise 决议(或拒绝)的值。
代码示例
应用场景:
- 同时上传多张图片,实现异步并发(例如使用阿里云 OSS 同时批量上传多张图片)
基本用法
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises).then((results) =>
  results.forEach((result) => console.log(result.status))
);
// 结果:
// fulfilled
// rejected
异步并发
let files = [{ file: new File() }, { file: new File() }];
const ossConfig = {
  accessKeyId: 'xxx',
  accessKeySecret: 'xxx',
  stsToken: 'xxx',
  bucket: 'xxx',
  region: xxx'',
};
function uploadFile(file) {
  return new Promise((resolve, reject) => {
    try {
      const filePath = genPath('');
      const client = new OSS(ossConfig);
      client.put(filePath, file).then(res => {
        if (res?.res?.status === 200) {
          resolve(res.url);
        } else {
          reject('上传失败');
        }
      });
    } catch (err) {
      reject(err);
    }
  });
}
async function uploadFiles(files) {
  const promises = [],
    urls = [];
  try {
    for (const item of files) {
      const promise = uploadFile(item.file);
      promises.push(promise);
    }
    const result = await Promise.allSettled(promises);
    urls = result.reduce((acc, item) => {
      if (item.status === 'fulfilled') {
        acc.push({ url: item.value });
      }
      return acc;
    }, []);
  } catch (err) {
    console.log(err);
  }
  return urls;
}