拒绝后承诺链继续



我很难在promise链中正确捕获错误/拒绝。

const p1 = () => {
return new Promise((resolve, reject) => {
console.log("P1");
resolve();
});
};
const p2 = () => {
return new Promise((resolve, reject) => {
console.log("P2");
reject();
});
};

const p3 = () => {
return new Promise((resolve, reject) => {
console.log("P3");
resolve();
});
};
p1().catch(() => {
console.log("Caught p1");
}).then(p2).catch(() => {
console.log("Caught p2");
}).then(p3).catch(() => {
console.log("Caught p3");
}).then(() => {
console.log("Final then");
});

当promise被拒绝时,下面的.then仍然被执行。在我的理解中,当承诺链中发生错误/拒绝时,它后面的.then调用将不再执行。

P1
P2
Caught p2
P3
Final then

拒绝得到了正确的捕捉,但为什么是";P3";捕获后记录?

我做错了什么?

为了澄清@evolutionxbox,这是我预期的结果:

Promise.resolve().then(() => {
console.log("resolve #1");
return Promise.reject();
}).then(() => {
console.log("resolve #2");
return Promise.resolve();
}).then(() => {
console.log("resolve #3");
return Promise.resolve();
}).then(() => {
console.log("Final end");
}).catch(() => {
console.log("Caught");
});

这段代码的工作原理和它应该的完全一样。我看不出我的代码有什么不同,只是我单独声明了函数。

无论承诺在哪里被拒绝,上面的代码都会停止。

以下是您的代码的同步等价物:

const f1 = () => {
console.log("F1");
};
const f2 = () => {
console.log("F2");
throw new Error();
};
const f3 = () => {
console.log("F3");
};
try {
f1();
} catch {
console.log("Caught f1");
}
try {
f2();
} catch {
console.log("Caught f2");
}
try {
f3();
} catch {
console.log("Caught f3");
}
console.log("Final code");

正如你所看到的,这给出了一个匹配的结果。希望通过查看同步代码,您不会对原因感到惊讶。在try..catch中,您可以尝试恢复。其想法是catch停止错误传播,并且您有望继续。或者,如果你确实想停止,你仍然需要再次明确地throw,例如:

doCode();
try {
makeCoffee();
} catch(err) {
if (err instanceof IAmATeapotError) {
//attempt recovery
makeTea();
} else {
//unrecoverable - log and re-throw
console.error("Fatal coffee related issue encountered", err);
throw err;
}
}
doCode();

这也是Promise#catch()的作用,因此您可以尝试恢复,或者至少在出现问题时采取行动。这个想法是.catch()之后,您可能能够继续:

const orderPizza = (topping) => 
new Promise((resolve, reject) => {
if (topping === "pepperoni")
reject(new Error("No pepperoni available"));
else
resolve(`${topping} pizza`);
});
const makeToast = () => "toast";
const eat = food => console.log(`eating some ${food}`);
async function main() {
await orderPizza("cheese")
.catch(makeToast)
.then(eat);

console.log("-----");

await orderPizza("pepperoni")
.catch(makeToast)
.then(eat);
}
main();

为了拒绝来自.catch()的承诺链,您需要执行与正常catch类似的操作,并且在错误恢复时通过引发另一个错误而失败。您可以throw或返回一个被拒绝的承诺。

这段代码的工作原理与它应该的完全一样。我看不出我的代码有什么不同,只是我单独声明了函数。

无论承诺在哪里被拒绝,上面的代码都会停止。

您显示的第二段代码在拒绝后完全失败,因为没有其他.catch()-es成功。它基本上类似于这个同步代码:

try {
console.log("log #1");
throw new Error();
console.log("log #2");
console.log("log #3");
console.log("Final end");
} catch {
console.log("Caught");
}

因此,如果不想尽早恢复,也可以跳过.catch(),而不是引发另一个错误。

试试这个。

const p1 = (arg) => {
// Promise returns data in the respected arguments
return new Promise((resolve, reject) => {
// Data to be accessed through first argument.
resolve(arg);
});
};

const p2 = (arg) => {
return new Promise((resolve, reject) => {
// Data to be accessed through second argument.
reject(arg);
});
}
p1('p1').then(resolve => {
console.log(resolve + ' is handled with the resolve argument. So it is accessed with .then()');
}) // Since reject isn't configured to pass any data we don't use .catch()
p2('p2').catch(reject => {
console.log(reject + ' is handled with the reject argument. So it is accessed with .catch()');
}) // Since resolve ins't configured to pass any data we don't use .then()
// You would normally configure a Promise to return a value on with resolve, and access it with .then() when it completes a task successfully.
// .catch() would then be chained on to the end of .then() to handle errors when a task cannot be completed.
// Here is an example.
const p3 = () => {
return new Promise((resolve, reject) => {
var condition = true;
if (condition === true) {
resolve('P3');
} else {
reject('Promise failed!');
}
});
};
p3('p3').then(resolve => {
console.log(resolve);
}).catch(reject => {
console.log(reject);
})

您没有做错任何事。在代码中,您将第一个promise称为p1。然后你写p1.catch(...).then(...).then(...).then(...)。这是一个链,意味着您应该调用then3次,因为您在p1promise中调用了resolve方法(所有这些then都取决于第一个promise)。

当promise被拒绝时,以下.then仍然被执行。

是。准确地说:thencatch方法调用都是同步执行的(一次性执行),因此所有涉及的promise都是一次性创建的。传递给这些方法的回调异步执行,正如相关的promise所解决的那样(fullfill或reject)。

根据我的理解,当在承诺链中发生错误/拒绝时,随后的.then调用将不再执行。

事实并非如此。catch返回的promise可以完全填充,也可以拒绝,这取决于传递给它的回调中发生了什么,因此当该promise解析时,链下游的回调将相应地执行。

拒绝被正确捕捉,但为什么是"P3";捕获后记录?

在您的情况下,catch回调返回undefined(它只执行console.log),其promisefullfulls!因此,链式then回调——在承诺的上——被执行。。。等

如果你想";停止">

如果你想保持链的原样,但希望出现拒绝导致不再执行thencatch回调的行为,那么不要解决相关的承诺:

const stop = new Promise(resolve => null);
const p1 = () => {
return new Promise((resolve, reject) => {
console.log("P1");
resolve();
});
};
const p2 = () => {
return new Promise((resolve, reject) => {
console.log("P2");
reject();
});
};

const p3 = () => {
return new Promise((resolve, reject) => {
console.log("P3");
resolve();
});
};
p1().catch(() => {
console.log("Caught p1");
return stop; // don't resolve
}).then(p2).catch(() => {
console.log("Caught p2");
return stop;
}).then(p3).catch(() => {
console.log("Caught p3");
return stop;
}).then(() => {
console.log("Final then");
});

相关内容

  • 没有找到相关文章

最新更新