我试图了解 Promise 执行器中抛出错误和异常(代码错误)情况下的 Promise 错误处理,并将它们与拒绝进行比较。这是针对 Node.js 的。
拒绝与抛出和异常的处理似乎存在明显差异。
一些网络文章暗示 Promise 周围有一个隐式的 try/catch,可以将异常和抛出转换为拒绝,但显然这不是真的,或者并不总是如此。
我写了一些测试代码来研究它。该代码和结果如下。
测试代码:
function delay(ms) {
return new Promise((resolve, reject) => {
setTimeout(value => {
resolve();
}, ms);
});
}
function f(delayMs, action) {
return new Promise((resolve, reject) => {
if (delayMs == 0) {
console.log(`f() forcing error type ${action} sync...`);
if (action == 'exception') {
console.xxx();
} else if (action == 'throw') {
throw new Error('thown error sync');
} else {
reject('reject sync');
}
} else {
delay(delayMs).
then(() => {
console.log(`f() forcing error type ${action} after delay...`);
if (action == 'exception') {
console.yyy();
} else if (action == 'throw') {
throw new Error('thrown error after delay');
} else {
reject('reject after delay');
}
});
}
});
}
function main(delayMs, action) {
f(delayMs, action).
then(value => {
console.log('Should not see this');
}).
catch(err => {
if (typeof err == 'object') console.log('In main catch:', err.message);
else console.log('In main catch:', err);
}).
finally(() => {
console.log('In main finally');
});
}
main(0, 'exception');
main(0, 'throw');
main(0, 'reject');
main(500, 'reject');
main(1000, 'exception');
main(1500, 'throw');
输出:
f() forcing error type exception sync...
f() forcing error type throw sync...
f() forcing error type reject sync...
In main catch: console.xxx is not a function
In main catch: thown error sync
In main catch: reject sync
In main finally
In main finally
In main finally
f() forcing error type reject after delay...
In main catch: reject after delay
In main finally
f() forcing error type exception after delay...
/mnt/c/Users/test/promise-stackoverflow-2.js:25
console.yyy();
^
TypeError: console.yyy is not a function
at /mnt/c/Users/test/promise-stackoverflow-2.js:25:33
Node.js v18.12.1
对于同步情况,所有三种错误类型的处理方式相同,在主函数的 catch 中捕获。
对于异步情况,确实涉及另一个 Promise,拒绝情况仍然在主函数的 catch 中处理。但另外两种情况(异常和抛出)会导致更高级别的异常并且进程退出。
看起来我可以为delay() promise 添加一个catch处理程序,然后在该catch中执行拒绝,它将传播到主catch处理程序。我认为我不需要这样做 - 我错过了什么吗?
此外,一些文章暗示使用 async/await 可以更轻松地处理错误。对我来说,如果你想进行严格的错误处理,只使用 promise 会更容易。
最佳答案
当你这样做时delay().then()
然后扔进.then()
,该 throw 被 .then()
捕获并变成了被拒绝的 promise 。那次 throw 没有进入 try/catch
的执行人。然后,您没有任何代码来捕获或处理该拒绝,因此您会得到未处理的拒绝。
有一个自动try/catch
围绕 Promise 执行器,但只能捕获该函数顶层抛出的异常,而不是未处理的 Promise 拒绝。
讨论如何修复这种代码结构并没有什么指导意义,因为你真的不应该这样做 fn().then()
无论如何,在 promise 执行者内部。此时,您正在用另一个不必要的 promise 手动包装 promise 。外部的、手动创建的 Promise 是不必要的。
It looks like I can add a catch handler for the delay() promise, and then do a reject in that catch and it will propagate to the main catch handler. I didn't think I would need to do this - am I missing something?
是的,这将添加缺少的拒绝处理程序。但是,这在现实世界的编码中通常不应该发生,因为你不应该这样做 fn().then()
首先在 promise 执行者内部。
Also, some articles imply that error handling is easier using async/await. To me, it seemed like if you want to do strict error handling, just using promises was easier.
凭借一些经验,您会发现使用 Promise 进行编码通常更简单,使用 async/await
,特别是当您遇到更复杂的场景(例如多个有序异步操作和异步操作分支)时。单链
无论哪种方式都可以轻松完成操作。
使用 async/await
有时错误处理会更简单有时不是。这实际上取决于具体情况以及您希望如何处理本地/全局错误。使用 .catch()
在本地处理拒绝(直接根据立即 promise )有时会更容易而集中拒绝处理,特别是当涉及多个 promise 链时,使用 async/await
可能会简单得多。和try/catch
。这实际上取决于代码的布局以及您需要在哪里捕获/处理错误。
此外,自动捕获同步异常并将其自动转换为拒绝在 async
中非常有用。函数也如此,因此您不必编写代码来处理同步异常和在可能发生的情况下被拒绝的 promise 。
关于javascript - 关于基于错误是同步还是异步的 Javascript Promise 错误处理差异的问题 (node.js),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75780095/