Promise.allSettled

⭐️ ES2020(ES11)新特性

Promise.allSettled 方法返回一个在所有给定的 Promise 都已经 fullfilledrejected 后的 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

valuereason 分别反映了每个 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;
}

参考资料