惯用的节点错误处理

Posted

技术标签:

【中文标题】惯用的节点错误处理【英文标题】:Idiomatic Node error handling 【发布时间】:2018-08-08 19:44:28 【问题描述】:

所以我正在做一个 nodejs 教程,它要求我使用模块来过滤目录中的所有文件。而且我应该使用惯用的方法来处理错误。下面是我的 modules.js 和我的 main program.js,但是,程序说

Your additional module file [module.js] does not appear to pass back an
error received from fs.readdir(). Use the following idiomatic Node.js
pattern inside your callback to fs.readdir():
if (err) return
callback(err)

但我确实使用if (err)return callback(err); 处理了第一行的错误

有人可以指出我做错了什么或我没有遵循什么最佳做法吗?谢谢

module.exports = function filterList(dirName, extName, callback) 

fs.readdir(dirName, function callback(err, list) 

    if (err)
        return callback(err);
    for (var i = 0; i < list.length; i++) 
        if (path.extname(list[i]) == '.' + extName) 
            callback(null, list[i]);
        
    ;
);

我的program.js如下

var myMod = require('./module');
function printOut(err, result) 
    if (err) 
        console.log(err);
    ;
    console.log(result);


myMod(process.argv[2], process.argv[3], printOut);

【问题讨论】:

【参考方案1】:

这里有两个名为 callback 的函数,这会导致意外行为。

您的主要导出函数采用参数名称callback。然后在其中定义另一个名为 `callback' 的函数:

function filterList(dirName, extName, callback) // <-- callback as arg
    fs.readdir(dirName, function callback(err, list)  // <-- callback defined again
        if (err)
          return callback(err);  // <-- which function is this calling?
  /* etc. */

当您最终return callback(err) 时,您调用了错误的函数。您想调用第一个——传递给filterList() 的那个,但第二个在范围内。

您可以改为将匿名函数传递给fs.readdir,因为您永远不需要调用它:

 fs.readdir(dirName, function(err, list) 
    if (err)
      return callback(err);  // <-- now there's only one call back

现在很明显,您正在调用正确的回调,而且更符合习惯。

【讨论】:

【参考方案2】:

您通过将函数命名为与参数相同的名称来隐藏您的callback。试试这个:

module.exports = function filterList(dirName, extName, callback) 
  fs.readdir(dirName, function cb(err, list) 
    if (err) return callback(err);
    for (var i = 0; i < list.length; i++) 
      if (path.extname(list[i]) == '.' + extName) 
        callback(null, list[i]);
      
    ;
  );

请注意,将第二个参数重命名为 fs.readdir 现在已命名为 cb,您实际上不需要命名它,但它确实有助于堆栈跟踪和日志记录。

另外,在循环中调用callback 时会遇到问题。有办法摆脱它,也有办法避免它陷入循环。

【讨论】:

以上是关于惯用的节点错误处理的主要内容,如果未能解决你的问题,请参考以下文章

Clojure 中的惯用错误处理

在golang中处理逻辑错误与编程错误的惯用方法

惯用的 goroutine 终止和错误处理

如何使用适用于 DynamoDb 的 AWS Rust 开发工具包编写惯用的 Rust 错误处理?

如果成功,从没有结果的函数返回错误的惯用方法是啥?

合并两种错误类型最惯用的方法是啥?