返回

同步异步混乱?教你用Promise在循环中保持序列执行

前端

前言

在前端开发中,我们经常需要在循环中执行异步任务。例如,我们需要从服务器端获取数据,然后根据这些数据渲染页面。如果这些异步任务是相互依赖的,那么我们就需要确保它们按照正确的顺序执行。否则,可能会导致数据不一致或页面渲染错误。

解决方案

1. for+async/await

for+async/await是一种非常简单的方法,它使用async/await语法来在循环中串行执行promise。

async function main() {
  const promises = [];
  for (let i = 0; i < 10; i++) {
    promises.push(new Promise((resolve) => {
      setTimeout(() => {
        resolve(i);
      }, 1000);
    }));
  }

  for await (const result of promises) {
    console.log(result);
  }
}

main();

这种方法非常直观,也很容易理解。但是,它也有一个缺点,那就是它不能处理错误。如果其中一个promise被拒绝了,那么整个循环都会被中断。

2. Array.prototype.reduce+async/await

Array.prototype.reduce+async/await是一种更健壮的方法,它可以使用async/await语法来在循环中串行执行promise,并且可以处理错误。

async function main() {
  const promises = [];
  for (let i = 0; i < 10; i++) {
    promises.push(new Promise((resolve) => {
      setTimeout(() => {
        resolve(i);
      }, 1000);
    }));
  }

  const results = await Promise.all(promises);

  results.forEach((result) => {
    console.log(result);
  });
}

main();

这种方法使用Promise.all()方法来等待所有promise都执行完毕。如果其中一个promise被拒绝了,那么Promise.all()方法会将这个promise的错误传递给reduce方法。reduce方法可以使用try/catch语句来捕获这个错误,并继续执行循环。

3. Arr.allSettled+async/await

Arr.allSettled+async/await是一种最健壮的方法,它可以使用async/await语法来在循环中串行执行promise,并且可以处理错误。

async function main() {
  const promises = [];
  for (let i = 0; i < 10; i++) {
    promises.push(new Promise((resolve) => {
      setTimeout(() => {
        resolve(i);
      }, 1000);
    }));
  }

  const results = await Promise.allSettled(promises);

  results.forEach((result) => {
    if (result.status === "fulfilled") {
      console.log(result.value);
    } else {
      console.error(result.reason);
    }
  });
}

main();

这种方法使用Promise.allSettled()方法来等待所有promise都执行完毕。Promise.allSettled()方法会返回一个数组,其中包含所有promise的结果。如果其中一个promise被拒绝了,那么Promise.allSettled()方法会将这个promise的结果状态设置为"rejected"。我们可以使用forEach方法来遍历这个数组,并根据promise的结果状态来决定如何处理结果。

比较

方法 优点 缺点
for+async/await 简单,易于理解 不能处理错误
Array.prototype.reduce+async/await 可以处理错误 稍微复杂一些
Arr.allSettled+async/await 最健壮,可以处理错误 最复杂

结论

在循环中串行执行promise有几种不同的方法。每种方法都有其优缺点。在选择方法时,您需要考虑您的具体需求。如果您需要一种简单、易于理解的方法,那么您可以使用for+async/await方法。如果您需要一种可以处理错误的方法,那么您可以使用Array.prototype.reduce+async/await方法或Arr.allSettled+async/await方法。