我正在使用 Node.JS 和一个基于事件的 API(串行端口),它提供
error
事件,并且我想通过当场抛出异常来处理错误。我明白这意味着我需要以更同步的方式做事。
但是,我很难找到直接的方法来做到这一点。我想出如何做到这一点的唯一方法是使用中间承诺以及
async
/await
,就像打开串行端口的示例(可以工作但似乎迂回):
import { SerialPort } from 'serialport';
import assert from 'node:assert';
// return port on success, throw something on error
async function openPort (path) {
const p = new SerialPort({path:path,baudRate:9600});
return await new Promise ((resolve, reject) => {
p.once('open', () => resolve(p));
p.once('error', e => reject(e));
}).catch(e => {
throw e;
});
}
// synchronously open the port and handle resulting exception
let port;
try {
port = await openPort('INVALIDPATH');
assert(port);
assert(port.port);
assert(port.port.isOpen);
console.log('port open');
} catch (e) {
console.log('failed:', e);
}
// continue doing other stuff (errors are not fatal)
console.log('continuing to do other stuff...');
我有两个问题:
error
事件在处理事件时抛出异常?await
时必须使用openPort()
?作为旁注,我认为我在上面的代码中看到了一个错误,其中
once('error',...)
事件处理程序将在成功打开时保持附加状态,因此如果稍后发生错误,它将返回并调用过时的事件处理程序。我想避免这种情况,因为稍后可能会发生其他 error
事件,我也想处理这些事件。
有没有一种方法可以[同步打开端口并处理产生的异常],但在调用
时不必使用await
?openPort()
不。
SerialPort
API 不会同步返回结果或引发错误。在此事件循环传递期间根本不知道成功/失败结果,这就是为什么您被迫使用回调来处理它。
Promise 是一个工具,用于从可能包含回调的任意代码中构建健壮、行为良好的“thenables”。使用它们将烦人的基于事件回调的临时 API 打包成更简单的 “您可以将
await
与” API 一起使用是非常合适的。
如果你对 Promises 过敏,你可以自己重新实现该功能,或者使用第三方替代方案,如 Continuation.js 或 Effection...但你为什么要这样做呢?
有没有更直接的方法让
事件在处理事件时抛出异常?error
如果您想让错误消失(也就是说,在事件循环中引发它并让它在未处理的情况下冒出,绝对没有编程结果,并且如果浏览器愿意的话,唯一的效果是控制台警告消息),你可以做这样的事情:
// BAD PRACTICE: throwing a non-Error object
// BAD PRACTICE: exception will be unhandled
SET_ERROR_CALLBACK (
(event) => {
throw event;
}
)
但是,如果您愿意使用 Promise 来桥接必须创建此事件循环传递的回调与您想要在结果上运行或引发的代码(这就是您当前正在做的事情),那就很好;我可能建议的唯一改进是构造一个合适的
Error
对象:
new Promise((resolve, reject) => {
/* … */
SET_OK_CALLBACK ( // For example, ".onsuccess =" or ".once('open'"
(event) => resolve(event.target.result) // or event.target if API doesn't use .result
)
SET_ERROR_CALLBACK ( // For example, ".onerror =" or ".once('error'"
(event) => reject(
new Error(`${event.target.__proto__.constructor.name}:${event.type}`, {cause: event})
)
)
)
当出现问题时,你会得到一个易于阅读的错误: