• 作者:老汪软件技巧
  • 发表时间:2024-09-10 11:01
  • 浏览量:

作为一名资深前端专家,我经常需要处理并行任务,以提高开发效率和用户体验。今天,我将通过一个生活化的例子,展示如何使用JavaScript中的Promise来并行处理任务,并优雅地处理结果。

场景设定

想象一下,你的另一半给你分配了几个家务任务,每个任务都可以看作是一个Promise。你需要同时启动这些任务,并在所有任务结束后汇报工作结果。这不仅是一个生活技能,也是前端开发中常见的并行任务处理场景。

代码实现

我们首先定义了三个函数:cook、wash和sweep,每个函数返回一个Promise,模拟做饭、洗衣服和打扫卫生的过程。

// 做饭、洗衣服、打扫卫生的模拟函数
// 做饭
function cook() {
  return new Promise((resolve, reject) => {
    console.log('邓哥打开了电饭煲');
    setTimeout(() => {
      if (Math.random() < 0.5) {
        resolve('饭已ok');
      } else {
        reject('做饭却忘了加水,米饭变成了爆米花');
      }
    }, 2000);
  });
}
​
// 洗衣服
function wash() {
  return new Promise((resolve, reject) => {
    console.log('邓哥打开了洗衣机');
    setTimeout(() => {
      if (Math.random() < 0.5) {
        resolve('衣服已经洗好');
      } else {
        reject('洗衣服时停水了,洗了个寂寞');
      }
    }, 2500);
  });
}
​
// 打扫卫生
function sweep() {
  return new Promise((resolve, reject) => {
    console.log('邓哥打开了扫地机器人');
    setTimeout(() => {
      if (Math.random() < 0.5) {
        resolve('地板扫的非常干净');
      } else {
        reject('扫地机器人被哈士奇一爪掀翻了');
      }
    }, 3000);
  });
}

Promise的静态方法

在处理并行任务时,我们可以使用Promise的几种静态方法来控制任务的执行流程:

前端并发处理_前端并行请求_

练习题

接下来,我们通过一个实际的练习题来加深理解。假设我们需要根据页码获取学生数据,并处理可能出现的错误。

// 获取学生数据的模拟函数
/**
 * 根据页码获取学生数据,返回Promise
 * @param {Number} page 页码
 */
function fetchStudents(page) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.3) {
        reject(new Error(`网络错误!获取第${page}页数据失败!`));
        return;
      }
      // 模拟学生数据
      const stus = new Array(10).fill(null).map((d, i) => ({
        id: `NO.${(page - 1) * 10 + i + 1}`,
        name: `姓名${(page - 1) * 10 + i + 1}`,
      }));
      resolve(stus);
    }, Math.floor(Math.random() * 5000));
  });
}
​
// 利用 fetchStudents 函数,完成下面的练习// 获取1-10页的学生,最终按照页码的顺序合并成一个数组,任何一页的数据获取出现错误,则任务不再继续,打印错误消息
Promise.all(proms)
  .then((result) => {
    console.log(result.flat());
  })
  .catch((err) => {
    console.log(err);
  });
​
​
// 获取1-10页的学生,最终按照页码的顺序合并成一个数组,如果某些页码的数据获取失败,就不加入该数据即可
Promise.allSettled(proms).then((result) => {
  result = result
    .filter((r) => r.status === 'fulfilled')
    .map((it) => it.value)
    .flat();
  console.log(result);
});
​
// 获取1-10页的学生,打印最先获取到的数据,如果全部都获取失败,则打印所有的错误消息
Promise.any(proms)
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {
    console.log(err.errors);
  });
​
​
// 获取1-10页的学生,输出最先得到的结果(有结果输出结果,有错误输出错误)
Promise.race(proms).then(
  (result) => {
    console.log(result);
  },
  (err) => {
    console.log(err);
  }
);

我们使用Promise.all、Promise.allSettled、Promise.any和Promise.race来处理不同情况下的数据获取。

场景解决方案

最后,我们将上述家务任务的解决方案实现如下:

// 并行执行家务任务并汇总结果
Promise.allSettled([cook(), wash(), sweep()]).then((result) => {
  // 处理汇总结果
  const report = result
    .map((r) => (r.status === 'fulfilled' ? r.value : r.reason))
    .join(';');
  console.log(report);
});

结论

通过这个例子,我们可以看到Promise在并行任务处理中的强大能力。在工作中,合理利用Promise可以大大提高我们的效率和处理复杂问题的能力。