我有一个如下的任务,我必须在 JavaScript 中使用 Promise Chaining 来解决它,并且我得到了一些意想不到的输出 -:
如果迈克能够打扫房间,那么他就会去踢足球。 在足球比赛中,如果他进球,那么作为奖励,他将有机会参观音乐会。如果他没有进球,他就会清理他的狗。 如果他不能打扫房间,他就会洗衣服。 如果他也无法洗完衣服,那么他就必须清理他的狗。 但如果他能洗干净衣服,他就会去听音乐会。
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
现在我的问题是,如果房间没有打扫那么为什么会打印“房间已打扫......”?如果最初的 Promise 被拒绝,那么控件应该转到代码的第二个 .catch() ,然后如果第二个 Promise 也被拒绝,那么控件应该转到最后一个 .catch() ,就是这样。为什么这没有发生?
其中一个可能的预期输出将类似于-:
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
上述任务和代码基于 Praveen Gaur 的 “JavaScript Promises” Medium 文章。
如果您有一个被拒绝的 Promise,并且将单参数
then
子句链接到它,则这些 then
子句返回的 Promise 将以与原始方式相同的方式被拒绝。这是因为then
的定义中的规则:
如果它 [onFulfilled] 不是一个函数,它会在内部被替换为一个恒等函数 (
),该函数只是向前传递履行值。(x) => x
如果它 [onRejected] 不是一个函数,它会在内部被替换为抛出函数 (
),该函数会抛出收到的拒绝原因。(x) => { throw x; }
在这里,你的
cleanRoom
被拒绝了;您在没有 then
处理程序的情况下链接了两个 onRejected
调用,因此当您到达 catch
子句时,您的 Promise 仍以其初始状态被拒绝。您读到的文章没有充分描述这种情况。
const roomCleaningPromise = Promise.reject(new Error("original failure"));
roomCleaningPromise.then(function goFootballAfterCleaning(resolveValue) {
console.log("this doesn't run, roomCleaningPromise failed");
}).then(function goConcertAfterGoal(resolveValue) {
console.log("this doesn't run, roomCleaningPromise failed");
}).catch(function cleanDogAfterLosing(errorValue) {
console.log(`Catch #1, value: ${errorValue}`);
})
roomCleaningPromise.catch(function goLaundryAfterNoCleaning(errorValue) {
console.log(`Catch #2, value: ${errorValue}`);
return new Promise(function doLaundry(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(`Laundry + concert: ${resolveValue}`);
}).catch(function cleanDogAfterNoLaundary(errorValue){
console.log(`Laundry + dog: ${errorValue}`);
})
传播错误的能力应该被视为 Promise 的一项功能,并且近似于以异步方式使用
try
/catch
:
function main() {
try {
a();
} catch(e) {
console.log(e);
}
}
function a() {
b();
console.log("this doesn't happen because b throws");
}
function b() {
throw new Error("this is logged by main despite not being handled in a");
}