如何处理异步函数mpv.getProperty抛出的未捕获错误?
MPV异步函数未捕获Socket错误的处理方案
问题背景
这个问题并非讨论Promise拒绝的重复问题,我无法修改mpv.getProperty的行为,请求重新开放问题。
我在使用异步函数mpv.getProperty时遇到了一个问题:该函数有时会触发未捕获的错误,而非返回Promise拒绝,导致常规的.catch和try-catch都无法捕获,服务器直接崩溃。
我尝试过用try-catch包裹调用,也写了包装函数,但都无效,代码如下:
app.get('/filename', (req, res) => { async function getFilenameProperty() { try { return await mpv.getProperty("filename") } catch (error) { console.log(error) } } getFilenameProperty().then((f) => { res.status(200).send(f) }).catch((error) => { console.log(error) res.status(400).send(`Error getting filename`) }) })
复现步骤
- 创建Express服务器,导入node-mpv库
- 初始化实例:
const mpv = new mpvAPI({"verbose": true}, ["--fullscreen"]) const app = express()
- 配置上述
/filename端点,发送GET请求后服务器直接崩溃
错误信息
node:events:495 throw er; // Unhandled 'error' event ^ Error [ERR_SOCKET_CLOSED]: Socket is closed at new NodeError (node:internal/errors:405:5) at Socket._writeGeneric (node:net:953:8) at Socket._write (node:net:975:8) at writeOrBuffer (node:internal/streams/writable:392:12) at _write (node:internal/streams/writable:333:10) at Writable.write (node:internal/streams/writable:337:10) at /hot/GitHub/remotetv-fullstack-project/back/node_modules/node-mpv/lib/ipcInterface/ipcInterface.js:209:17 at new Promise (<anonymous>) at ipcInterface.send (/hot/GitHub/remotetv-fullstack-project/back/node_modules/node-mpv/lib/ipcInterface/ipcInterface.js:190:10) at ipcInterface.getProperty (/hot/GitHub/remotetv-fullstack-project/back/node_modules/node-mpv/lib/ipcInterface/ipcInterface.js:117:15) Emitted 'error' event on Socket instance at: at emitErrorNT (node:internal/streams/destroy:151:8) at emitErrorCloseNT (node:internal/streams/destroy:116:3) at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { code: 'ERR_SOCKET_CLOSED' }
为什么原来的代码无效?
从错误栈可以看出,这个错误是Socket实例触发的未捕获error事件,既不是mpv.getProperty返回的Promise拒绝,也不是同步抛出的错误。
在Node.js中,所有EventEmitter实例如果触发了error事件但没有绑定对应的监听器,就会直接抛出错误并终止进程。这种异步事件触发的错误不在当前函数调用栈里,所以try-catch和Promise的.catch都无法捕获。
解决方案
1. 监听底层Socket的error事件
找到mpv实例底层的Socket对象,给它绑定error监听器,就能直接捕获这类错误:
// 初始化mpv后立即绑定 const mpv = new mpvAPI({"verbose": true}, ["--fullscreen"]); // 访问mpv的IPC接口对应的Socket(根据node-mpv的内部结构) if (mpv.ipcInterface?.socket) { mpv.ipcInterface.socket.on('error', (err) => { console.log('MPV Socket错误捕获:', err); // 可以在这里处理连接异常,比如标记连接状态、尝试重连等 }); }
2. 监听mpv实例的自定义错误事件
查看node-mpv文档,部分库会在底层出错时暴露自定义错误事件,可以直接监听mpv实例的error事件:
mpv.on('error', (err) => { console.log('MPV实例错误:', err); });
3. 全局异常监听(临时应急方案)
如果找不到具体的事件源,可以临时给进程绑定全局监听,但不推荐作为长期方案,因为会掩盖其他未知错误:
process.on('uncaughtException', (err) => { console.log('未捕获全局异常:', err); // 根据错误码判断是否是Socket关闭错误 if (err.code === 'ERR_SOCKET_CLOSED') { // 针对性处理,比如重启mpv连接 } });
优化后的端点代码
结合Socket错误监听,调整后的端点代码可以避免服务器崩溃:
// 初始化并绑定错误监听 const mpv = new mpvAPI({"verbose": true}, ["--fullscreen"]); if (mpv.ipcInterface?.socket) { mpv.ipcInterface.socket.on('error', (err) => { console.log('MPV Socket错误:', err); }); } // 简化后的端点处理 app.get('/filename', async (req, res) => { try { const filename = await mpv.getProperty("filename"); res.status(200).send(filename); } catch (err) { console.log('获取文件名失败:', err); res.status(400).send('获取文件名失败'); } });
内容的提问来源于stack exchange,提问作者Omaro_IB
相关产品推荐
相关产品推荐

