nos*_*tio 10 javascript node.js promise async-await es6-promise
更新,我现在已经尝试解释我所看到的行为,但从可靠的来源获得关于行为的答案仍然很棒unhandledRejection。我还在Reddit 上发起了一个讨论。
为什么我unhandledRejection在下面的代码中得到一个事件(对于“错误 f1”)?这是出乎意料的,因为我在处理这两个拒绝finally的部分main。
我在 Node (v14.13.1) 和 Chrome (v86.0.4240.75) 中看到了相同的行为:
window.addEventListener("unhandledrejection", event => {
console.warn(`unhandledRejection: ${event.reason.message}`);
});
function delay(ms) {
return new Promise(r => setTimeout(r, ms));
}
async function f1() {
await delay(100);
throw new Error("error f1");
}
async function f2() {
await delay(200);
throw new Error("error f2");
}
async function main() {
// start all at once
const [p1, p2] = [f1(), f2()];
try {
await p2;
// do something after p2 is settled
await p1;
// do something after p1 is settled
}
finally {
await p1.catch(e => console.warn(`caught on p1: ${e.message}`));
await p2.catch(e => console.warn(`caught on p2: ${e.message}`));
}
}
main().catch(e => console.warn(`caught on main: ${e.message}`));Run Code Online (Sandbox Code Playgroud)
好吧,回答我自己。我误解了unhandledrejection事件的实际运作方式。
我来自 .NET,在那里失败的Task对象可以保持不被观察到,直到它被垃圾收集。只有这样UnobservedTaskException才会被解雇,如果任务仍然未被观察到。
JavaScript 承诺的情况有所不同。被拒绝Promise该没有拒绝处理程序已经连接(通过then,catch,await或Promise.all/race/allSettle/any),需要一个尽可能早地,否则unhandledrejection事件可被触发。
如果unhandledrejection有的话,什么时候会被解雇?这似乎是特定于实现的。W3C 关于“未处理的承诺拒绝”的规范没有严格规定 用户代理何时通知被拒绝的承诺。
为了安全起见,我会在当前函数将执行控制权交给调用者之前同步附加处理程序(通过诸如return, throw, await, 之类的东西yield)。
例如,以下不会触发unhandledrejection,因为在承诺在已经被拒绝的状态下创建之后,await继续处理程序p1同步附加到p1。那讲得通:
window.addEventListener("unhandledrejection", event => {
console.warn(`unhandledRejection: ${event.reason.message}`);
});
async function main() {
const p1 = Promise.reject(new Error("Rejected!"));
await p1;
}
main().catch(e => console.warn(`caught on main: ${e.message}`));Run Code Online (Sandbox Code Playgroud)
unhandledrejection即使我们异步附加await处理程序,以下仍然不会触发p1。我只能推测,这可能会发生,因为已解决的承诺的延续被发布为一个微任务:
window.addEventListener("unhandledrejection", event => {
console.warn(`unhandledRejection: ${event.reason.message}`);
});
async function main() {
const p1 = Promise.reject(new Error("Rejected!"));
await Promise.resolve();
await p1;
}
main().catch(e => console.warn(`caught on main: ${e.message}`));Run Code Online (Sandbox Code Playgroud)
Node.js(发布时为 v14.14.0)与浏览器行为一致。
现在,以下内容确实会触发该unhandledrejection事件。再次,我可以推测这是因为在await处理任务(宏任务)队列p1时,继续处理程序现在异步附加到事件循环的某些后续迭代中:
window.addEventListener("unhandledrejection", event => {
console.warn(`unhandledRejection: ${event.reason.message}`);
});
async function main() {
const p1 = Promise.reject(new Error("Rejected!"));
await new Promise(r => setTimeout(r, 0));
await p1;
}
main().catch(e => console.warn(`caught on main: ${e.message}`));Run Code Online (Sandbox Code Playgroud)
我个人觉得这整个行为令人困惑。我喜欢 .NET 方法来Task更好地观察结果。我可以想到很多情况,当我真的想保留对承诺的引用,然后await在以后的时间线上捕获任何错误,以解决或拒绝。
也就是说,有一种简单的方法可以在不引起unhandledrejection事件的情况下获得此示例所需的行为:
window.addEventListener("unhandledrejection", event => {
console.warn(`unhandledRejection: ${event.reason.message}`);
});
async function main() {
const p1 = Promise.reject(new Error("Rejected!"));
p1.catch(console.debug); // observe but ignore the error here
try {
await new Promise(r => setTimeout(r, 0));
}
finally {
await p1; // throw the error here
}
}
main().catch(e => console.warn(`caught on main: ${e.message}`));Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2550 次 |
| 最近记录: |