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
相关产品推荐
相关产品推荐

