如何在使用 NodeJS 的 readline 模块时正确处理错误

时间:2021-02-17 00:04:22

标签: node.js async-await

我正在尝试逐行读取和处理文件。我想使用 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 }) 

没有成功。

1 个答案:

答案 0 :(得分:1)

try/catch 只捕获同步错误。所以它不会从 rl.on() 内部捕获任何东西。执行 await once() 只是在执行 console.log('File processed.'); 之前等待流 rl,但 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()

我个人喜欢在每个错误发生的地方处理它们。但是有些人喜欢用 err 处理程序在一个地方处理它们。在这种情况下,我们可以用一个 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()