JavaScript try块抛出异常后catch块未立即执行问题求助
问题原因
- Node.js 的 EventEmitter 事件机制不会等待异步回调执行完成。你在
parser中给data事件绑定了 async 回调,但parseFile触发data事件时,只会执行回调逻辑,不会等待回调返回的 Promise 变更状态,就会继续触发下一行的data事件。3行数据的rowCb回调几乎是同时启动的,启动后第一时间就把共享变量recordsProcessed自增到了3,三个processRow同时进入异步等待状态。 - 异步回调的闭包捕获的是
recordsProcessed变量的引用,而非触发回调时的瞬时值。等三个processRow先后抛出异常进入catch块时,共享的recordsProcessed已经被修改为3,所以所有报错都会打印Failure at record 3。
修复方案
方案1:串行逐行处理(完全符合预期执行顺序)
如果要求严格按文件行顺序处理,前一行处理完成后再处理下一行,需要改造 parser 函数,先收集所有行再串行消费:
async parser(fileBuffer: Buffer, rowCb: (row: Record<string, any>) => Promise<void>, ...) : Promise<number> { return new Promise((resolve, reject) => { const rows: Record<string, any>[] = [] parseFile(fileBuffer, options) .on('error', (error:any) => reject(error)) .on('data', row => rows.push(row)) .on('end', async (count: any) => { // 串行逐行执行回调 for (const row of rows) { try { await rowCb(row) } catch (e) { return reject(e) } } resolve(count) }) }) }
方案2:保留并行处理,修复行号打印问题
如果允许并行处理行数据,只需要修复行号打印错误的问题,不用修改 parser,只需要在回调内部存储当前行号的局部副本即可:
let recordsProcessed = 0 await parser(fileBuffer, async (row: Record<string, any>) => { recordsProcessed += 1 // 存储当前行号的局部副本,不会被后续自增修改 const currentRecordNo = recordsProcessed try { console.log('Processing record', currentRecordNo) await processRow(row) } catch (e) { console.log('Failure at record', currentRecordNo) } } )
内容的提问来源于stack exchange,提问作者user2943799
相关产品推荐
相关产品推荐

