MST

星途 面试题库

面试题:JavaScript Promise链式调用中的并发与错误传播机制深度探究

有多个Promise任务,其中部分任务可以并发执行(例如任务A、B、C),并发执行的任务全部完成后,再执行依赖它们结果的任务D。假设任务A、B、C、D都可能抛出错误,要求:1. 实现上述任务流程,保证并发任务的执行效率;2. 设计一种全面的错误处理机制,当任何一个任务出错时,能够正确终止相关任务(比如如果任务A出错,任务D不执行,且任务B和C可以选择是否继续执行),并将所有错误信息按照发生顺序收集起来返回,同时要确保错误不会在链式调用中被遗漏处理。请详细阐述你实现的思路以及对Promise并发和错误传播机制的理解。
27.7万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 并发任务执行:使用 Promise.all 来并发执行任务A、B、C。Promise.all 会返回一个新的Promise,只有当传入的所有Promise都resolved时,这个新Promise才会resolved,并且其resolved的值是一个包含所有传入Promise resolved值的数组。
  2. 依赖任务执行:在 Promise.all 成功后,执行任务D,并将任务A、B、C的结果作为参数传递给任务D。
  3. 错误处理:为了全面处理错误并收集错误信息,使用 try...catch 块来捕获每个任务可能抛出的错误。在 catch 块中,将错误信息收集到一个数组中,并根据需求决定是否继续执行其他并发任务(例如任务B和C)。
  4. 链式调用中的错误处理:在整个链式调用中,确保每个 then 方法都有对应的 catch 方法,避免错误在链式调用中被遗漏处理。

代码示例

function taskA() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() < 0.5? resolve('A result') : reject(new Error('A error'));
    }, 1000);
  });
}

function taskB() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() < 0.5? resolve('B result') : reject(new Error('B error'));
    }, 1000);
  });
}

function taskC() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() < 0.5? resolve('C result') : reject(new Error('C error'));
    }, 1000);
  });
}

function taskD(aResult, bResult, cResult) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() < 0.5? resolve(`D result: ${aResult}, ${bResult}, ${cResult}`) : reject(new Error('D error'));
    }, 1000);
  });
}

function executeTasks() {
  const errorList = [];
  return Promise.all([taskA(), taskB(), taskC()])
  .then(([aResult, bResult, cResult]) => {
      return taskD(aResult, bResult, cResult);
    })
  .catch((error) => {
      errorList.push(error);
      // 这里可以根据需求决定是否继续执行其他任务
      // 例如:忽略任务A的错误,继续执行任务B和C
      return Promise.all([taskB(), taskC()])
      .then(([bResult, cResult]) => {
          return taskD(null, bResult, cResult);
        })
      .catch((innerError) => {
          errorList.push(innerError);
          return Promise.reject(errorList);
        });
    });
}

executeTasks()
  .then((result) => {
      console.log('Final result:', result);
    })
  .catch((errors) => {
      console.log('All errors:', errors);
    });

对Promise并发和错误传播机制的理解

  1. Promise并发Promise.all 允许并发执行多个Promise任务。它会等待所有传入的Promise都resolved后,返回一个resolved的Promise,其值为所有传入Promise resolved值组成的数组。这大大提高了任务执行效率,因为多个任务可以同时进行,而不需要等待前一个任务完成。
  2. 错误传播机制:当 Promise.all 中的任何一个Promise被rejected时,整个 Promise.all 会立即被rejected,并且其rejected的值就是第一个被rejected的Promise的rejected值。在链式调用中,错误会沿着 .then() 链一直传递,直到遇到一个 .catch() 块来处理它。如果没有 .catch() 块,错误会导致未处理的拒绝(unhandled rejection),这可能会导致程序出现难以调试的问题。因此,在编写Promise链式调用时,确保每个 then 方法都有对应的 catch 方法,或者在链的末尾添加一个全局的 catch 块来处理可能遗漏的错误,是非常重要的。