You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript Promise链式调用异常输出问题排查与修正问询

Promise链式调用逻辑错误排查与修复

任务逻辑

  • 若Mike成功打扫房间,则去踢足球:
    • 踢足球进球 → 去音乐会
    • 踢足球没进球 → 打扫狗窝
  • 若Mike未能打扫房间,则去洗衣服:
    • 洗完衣服 → 去音乐会
    • 没洗完衣服 → 打扫狗窝

问题代码

const cleanRoom = (resolve, reject) => {
    let num = Math.random();
    if (num >= .5) { 
      resolve(num); //room cleaned
    } else {
      reject(new Error(num)); //room not cleaned
    }
  }
const roomCleaningPromise = new Promise(cleanRoom);

roomCleaningPromise.then(function goFootballAfterCleaning(resolveValue) {
  console.log(`Room was cleaned so going to play Football -: ${resolveValue}`);
  return new Promise(function makeGoal(resolve, reject) {
    let number = Math.random();
    if (number >= .5) { //go to concert
      resolve(number);
    } else {
      reject(number); //dog cleaning
    }
  }) 
}).then(function goConcertAfterGoal(resolveValue) {
  console.log(`Room was cleaned so went to play Football and made a goal!! Now Going to Music concert -: ${resolveValue}`);
}).catch(function cleanDogAfterlosing(errorValue) {
  console.log(`Room was cleaned so went to play Football but couldn't make a goal so Cleaning the dog -: ${errorValue}`);
})
  
roomCleaningPromise.catch(function goLaundaryAfterNoCleaning(errorValue) {
  console.log(`Room was not cleaned so going to do Laundry -: ${errorValue}`);
  return new Promise(function doLaundary(resolve, reject) {
    let number_2 = Math.random();
    if (number_2 >= .5) { //go to concert
      resolve(number_2);
    } else {
      reject(number_2); //dog cleaning
    }
  })
}).then(function goConcertAfterLaundary(resolveValue) {
  console.log(`Room was not cleaned so went to do Laundry, which I completed so now going to Music Concert -: ${resolveValue}`);
}).catch(function cleanDogAfterNoLaundary(errorValue){
  console.log(`Room was not cleaned so went to do Laundry, which I didn't complete so cleaning the dog -: ${errorValue}`);
})

实际输出

Room was not cleaned so going to do Laundry -: Error: 0.10282616920143206
Room was cleaned so went to play Football but couldn't make a goal so Cleaning the dog -: Error: 0.10282616920143206
Room was not cleaned so went to do Laundry, which I didn't complete so cleaning the dog -: 0.3140749736813231

预期输出示例

Room was not cleaned so going to do Laundry -: Error: 0.10282616920143206
Room was not cleaned so went to do Laundry, which I didn't complete so cleaning the dog -: 0.3140749736813231

疑问解答

1. 为何Promise的then和catch方法返回的Promise实例会相关联?

不是then/catch返回的Promise关联,而是你给同一个初始Promise(roomCleaningPromise)挂载了两组完全独立的回调链。当初始Promise被拒绝时,所有挂载在它身上的错误回调都会触发——第一组链的then因为初始Promise拒绝没执行,直接走到了该链的catch块,这就是错误输出的原因。

2. 如何修改代码以实现符合预期的任务逻辑?

要把两条分支合并成一条完整的链式调用,让初始Promise的then处理成功分支,catch处理失败分支,分支内部完成后续流程,而不是给同一个Promise挂两条独立链。修改后的代码如下:

function cleanRoom() {
  return new Promise((resolve, reject) => {
    const num = Math.random();
    num >= 0.5 ? resolve(num) : reject(new Error(num));
  });
}

function playFootball() {
  return new Promise((resolve, reject) => {
    const num = Math.random();
    num >= 0.5 ? resolve(num) : reject(num);
  });
}

function doLaundry() {
  return new Promise((resolve, reject) => {
    const num = Math.random();
    num >= 0.5 ? resolve(num) : reject(num);
  });
}

// 主流程
cleanRoom()
  .then(cleanVal => {
    console.log(`Room was cleaned so going to play Football -: ${cleanVal}`);
    return playFootball();
  })
  .then(goalVal => {
    console.log(`Room was cleaned so went to play Football and made a goal!! Now Going to Music concert -: ${goalVal}`);
  })
  .catch(err => {
    if (err instanceof Error) {
      // 没打扫房间,走洗衣服流程
      console.log(`Room was not cleaned so going to do Laundry -: ${err}`);
      return doLaundry()
        .then(laundryVal => {
          console.log(`Room was not cleaned so went to do Laundry, which I completed so now going to Music Concert -: ${laundryVal}`);
        })
        .catch(laundryErr => {
          console.log(`Room was not cleaned so went to do Laundry, which I didn't complete so cleaning the dog -: ${laundryErr}`);
        });
    } else {
      // 踢足球没进球,打扫狗窝
      console.log(`Room was cleaned so went to play Football but couldn't make a goal so Cleaning the dog -: ${err}`);
    }
  });

3. 如何阻止catch块返回的拒绝Promise继续触发后续的catch块?

有两种实用方式:

  • 在catch块处理完错误后,返回一个resolved状态的Promise(比如return Promise.resolve()),这样后续会触发then而不是下一个catch。
  • 把可能出错的逻辑放在当前catch内部完成,不向外返回拒绝状态的Promise。

示例(在洗衣服的catch中阻止后续触发):

.catch(laundryErr => {
  console.log(`Room was not cleaned so went to do Laundry, which I didn't complete so cleaning the dog -: ${laundryErr}`);
  return Promise.resolve(); // 阻止后续catch触发
});

内容的提问来源于stack exchange,提问作者Intangible _pg18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:54:54