首页 > 解决方案 > 使用 NodeJS 的 readline 模块时如何正确处理错误

问题描述

我正在尝试逐行读取和处理文件。我想使用 try / catch 异步模式来做到这一点。下面是一个直接从 NodeJS 文档中提取的关于如何使用 readline 模块的示例。

const { once } = require('events');
const { createReadStream } = require('fs');
const { createInterface } = require('readline');

(async function processLineByLine() {
  try {
    const rl = createInterface({
      input: createReadStream('big-file.txt'),
      crlfDelay: Infinity
    });

    rl.on('line', (line) => {
      // Process the line.
    });

    await once(rl, 'close');

    console.log('File processed.');
  } catch (err) {
    console.error(err);
  }
})();

我认为这await once部分让我陷入了一个循环。如果在解析行时遇到错误,我想做什么:

    rl.on('line', (line) => {
    try {
      // Process the line. maybe error from parsing?
      JSON.parse(line) 
    } catch ( error ) {
      throw new Error("error while attempting to process json.")
    }

    });

可以访问外部 try / catch 块中新抛出的错误,例如:

    console.log('File processed.');
  } catch (err) {
    console.error(err);
    // should see "error while attempting to process json."
  }
})();

到目前为止,firebase 函数在没有到达外部 try/catch 块的情况下崩溃。我尝试将错误事件侦听器添加到 readline 流中,例如:

rl.on("error", () => { // throw error here }) 

没有成功。

标签: node.jsasync-await

解决方案


try/catch 只捕获同步错误。所以它不会从里面抓到任何东西rl.on()。在执行await once()之前只是等待流 rl 来执行,console.log('File processed.');但是try{}catch(e){}已经执行了,所以任何错误都不能被捕获。

rl.on('error', () => {}只会从 rl 流本身捕获错误,因此即使发生错误createReadStream('big-file.txt')也不会被捕获(并且由于它是异步的,最终的 catch(e) 也不会捕获它)。

要捕获 中发生的任何错误,rl.on('line ....'解决方案之一是拒绝该错误。async/await 函数中被拒绝的错误将像在同步流中一样被 catch()。

一个例子

  async function processLineByLine() {
            try{                   
    
                    async function run() {          
                            const rs = createReadStream(__filename)
                            // otherwise createReadStream() err are not handled
                            rs.on('error', () => {          
                                console.log('HandleReadStreanErr')
                            })     
    
                            const rl = createInterface({    
                              input: rs,                      
                              crlfDelay: Infinity             
                            })
                            
                            return new Promise((resolve, reject) => {
                            rl.on('line', (line) => {       
                                 try {                           
                                    throw new Error("error while attempting to process json.")
                                    resolve(console.log(line.toString()))
    
                                 } catch(e) {                    
                                    reject(e)                       
                                 }                               
    
                            })
                            })
                            
                            // handle specificaly the rl stream error
                            rl.on('error', () => console.log('errr rl stream'))
      
    
                            await once(rl, 'close');        
                            console.log('File processed.'); 
                    }
                    // await the overall execution for the catch() to wait
                    await run()
            
        } catch(e) {
                    // only rejected err reach here or the one happening synchronously
                    console.error('eeeeeee')        
        }
    }
processLineByLine()

我个人喜欢在靠近它们发生的地方处理每个错误。但是有些人喜欢用一个错误处理程序在一个地方处理它们。在这种情况下,我们可以用一个 Promise 包装整个执行

 async function processLineByLine() {
        try{
        
           async function run() {
        
            return new Promise(async (resolve, reject) => {
        
                const rs = createReadStream('khg.jk')
                rs.on('error', () => {
                    reject('HandleReadStreanErr')
                })
        
                const rl = createInterface({
                  input: rs,
                  crlfDelay: Infinity
                })
        
                rl.on('line', (line) => {
                     try {
                        // uncomment following err
                        // throw new Error("error while attempting to process json.")
                        resolve(console.log(line.toString()))
        
                     } catch(e) {
                        reject(e)
                     }
        
                })
        
                rl.on('error', () => reject('errr rl stream'))
        
        
                await once(rl, 'close');
                console.log('File processed.');
        
            })
           }
           await run()
        
           } catch(e) {
                console.error('set error handler: ', e)
           }
   }
   processLineByLine()

推荐阅读