npm 关于回调错误的指南

npm's guidelines on callback errors

我通读了 npm’s coding style guidelines 并发现了以下非常神秘的建议:

Be very careful never to ever ever throw anything. It’s worse than useless. Just send the error message back as the first argument to the callback.

它们到底是什么意思,如何实现这一行为?他们是否建议在自身内部调用回调函数?

以下是我使用异步 fs.readdir 方法的想法。

fs.readdir('./', function callback(err, files) {
  if (err) {
    // throw err  // npm says DO NOT do this!
    callback(err) // Wouldn’t this cause an infinite loop?
  }
  else {
    // normal stuff
  }
})

是的,那会导致无限循环。然而,他们并不是在谈论那种类型的回调。相反,npm 正在引用用于与您的模块交互的回调。

扩展您的示例:

module.exports = {
    getDirectoryFiles: function (directory, done) {
        fs.readdir(directory, function callback(err, files) {
            if (err) {
                return done(err);
            } else {
                return done(null, files);
            }
        })
    }
}

您应该将 err 传递给上述范围的回调,而不是传递给您当前正在处理的函数(在上述情况下,callback)。命名这些函数的唯一原因是为了帮助调试。

他们说不要 throw err 的原因是节点使用错误优先回调。每个人都希望您的库(如果它使用回调)将其错误作为第一个参数传播给回调。例如:

var yourLibrary = require("yourLibrary");

yourLibrary.getDirectoryFiles("./", function (err, files) {
    if (err) {
        console.log(err);
        // do something
    } else {
        // continue
    }
}

他们想说的是你应该设计你的模块,这样异步函数就不会抛出错误来捕获,而是在回调内部处理(就像在 fs.readdir 示例中你提供)...

所以,例如,这就是他们所说的你应该设计你的模块:

var example = {
    logString: function(data, callback){
      var err = null;
      if (typeof data === "string") {
        console.log(data);
      } else {
        err = {"message": "Data is not a string!"};
      }
      callback(err);
    }
}

他们希望您设计它,以便最终用户可以处理回调内部的错误,而不是使用 try/catch 语句...例如,当我们使用 example 对象时:

example.logString(123, function(err){
  // Error is handled in callback instead of try/catch
  if (err) console.log(err)
});

这将记录 {"message": "Data is not a string!"},因为数据没有 typeof 等于 "string"

这是他们所说的你应该避免的例子:

他们不希望您在处理异步回调时抛出错误...假设我们重新设计了模块,因此 logString 方法抛出错误而不是将其传递给回调...像这样:

var example = {
    logString: function(data, callback){
      if (typeof data === "string") {
        console.log(data);
      } else {
        // See, we're throwing it instead...
        throw {"message": "Data is not a string!"};
      }
      callback();
    }
}

有了这个,我们必须执行整个 try/catch 语句,否则你会得到一个未捕获的错误:

try {
  example.logString(321, function(){
    console.log("Done!")
  });
} catch (e) {
  console.log(e)
}

最后的想法/总结:

我认为 NPM 建议使用此方法的原因是因为它在异步方法内部更易于管理。

NodeJS 和 JavaScript 总体上喜欢拥有一个异步环境,非常高兴能将它全部压缩到一个地方,错误处理等等。

使用 try/catch,这只是您必须采取的额外步骤,因为它可以在回调内部轻松处理(如果您正在异步设计它,您应该这样做)。