【问题标题】:Resolve promises sequentially and break the sequence if one of the promises in the sequence throws an error [duplicate]如果序列中的一个promise抛出错误,则按顺序解决promise并中断序列[重复]
【发布时间】:2025-12-06 08:05:02
【问题描述】:

假设我有三个async 函数设置如下:

const stepOne = async () => { setTimeout(function() {
  console.log("step 1")
}, 3000)  }

const stepTwo = async () => { throw new Error("Error at step two") }

const stepThree = async () => { console.log("step 3") }

我将如何按顺序执行所有这些函数并在 stepTwo 中断承诺链,不允许 stepThree 函数运行?

所以,

正常顺序是这样的:stepOne --> stepTwo --> stepThree

在 stepTwo 引发错误的序列:stepOne --> stepTwo

stepTwo 抛出的错误需要在 end catch 块中被捕获。

更新#1:错过了问题的关键要素。 await 不能使用,因为这三个函数需要在非异步函数中调用。

示例:

const testFunc = () => { 
  
  resolve three promises 
  sequentially, break the promise chain when error is thrown 
  and ultimately, catch errors here
   
  }

【问题讨论】:

  • 一般:try { await stepOne(); await stepTwo(); await stepThree(): } catch ...。但是,您的 stepOne 不会等待 setTimeout 解决。如果不更改 stepOne 的实现,就无法等待 setTimeout...
  • @deceze:抱歉!等待不是一种选择。更新了我的问题。
  • 如果您不能使用await,那么您将无法通过try..catch 捕获错误。您需要将它们与旧的 then.then.catch 联系起来。
  • @deceze :是的,明白。但是,我想通知需要捕获错误。如果它具有误导性,则不应使用 try.. catch 块。我从问题中删除了它。
  • 所以:stepOne().then(stepTwo).then(stepThree).catch(e => console.error(e))...

标签: javascript node.js asynchronous ecmascript-6


【解决方案1】:

请尝试以下代码。您需要等待每个调用(stepOne、stepTwo 和 stepThree),以便在出现异常时不会进行下一次调用。

try {
    await stepOne();
    await stepTwo();
    await stepThree()
} catch (error) {
    console.log(error);
}

【讨论】:

  • 抱歉!等待不是一种选择。更新了我的问题。
  • 如果主函数不是异步的,你有 2 个选项。您可以将我的示例代码包装在 IIFE 中或使用 .then .then .catch
  • ( async ()=> {// 以上代码示例 })();应该工作
【解决方案2】:

如果您的步骤是返回 Promise 的函数,您可以创建一个包装函数,该函数将按顺序调用每个步骤并在步骤失败时中止,并记录哪个步骤失败的详细信息。

在这个例子中,每一步都有五分之一的几率失败。

// Make a step proc, that throws 1 time in 5
function createStep(index) {
    let error = (Math.random() < 0.2) ? new Error(`Step ${index+1} error`) : null ;
    return () => new Promise((resolve, reject) => setTimeout(error ? reject(error): resolve(`Step ${index+1} outcome`), 500));
}

async function runSteps(steps) {
   
   for(stepIndex = 0; stepIndex < steps.length; stepIndex++) {
       try {
         console.log(`Running step #${stepIndex+1}...`);
         let result = await steps[stepIndex]();
         console.log(`Step result:`, result);
       } catch (e) { 
         console.error(`An error occurred at step #${stepIndex+1}:`, e.message);
         break;
       }
       if (stepIndex === (steps.length -1) ) {
          console.log("All steps completed successfully");
       }
   }
}

let steps = Array.from( { length: 3 }, (v,k) => createStep(k));
runSteps(steps);

【讨论】:

  • 抱歉!等待不是一种选择。更新了我的问题。
【解决方案3】:

如果您解决来自 stepOne 的承诺,您的代码将起作用,因为 setTimeout 只是将函数添加到堆栈中,而不是等待它解决。

如果您要从 stepOne 返回一个 Promise 并在 console.log 之后解决它,那么 try catch 将等待 stepOne 并在 stepTwo 上捕获错误

这是您的代码示例

const stepOne = async () => {
    return new Promise((resolve, reject) => {
        setTimeout(function() {
            console.log("step 1")
            resolve(true);
        }, 3000)
    });
}

const stepTwo = async () => { throw new Error("Error at step two") }

const stepThree = async () => {
    return new Promise((resolve, reject) => {
        setTimeout(function() {
            console.log("step 3")
            resolve(true);
        }, 3000)
    });
}


(() => {
    stepOne()
        .then(stepTwo)
        .then(stepThree)
        .catch(error => {
            console.log(error);
        })  
})();

现在console.log 看起来像这样

step 1
Error: Error at step two
    at stepTwo (/home/user/develop/test/*.js:10:38)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)

【讨论】:

  • 抱歉!等待不是一种选择。更新了我的问题。
  • 如果您对This question already has answers here: 标志的给定答案不满意,我更新了我的答案
最近更新 更多