为什么节点更喜欢错误优先callback?

节点程序员通常使用这样一个范例:

var callback = function(err, data) { if (err) { /* do something if there was an error */ } /* other logic here */ }; 

为什么不简化接受只有一个参数,这是一个错误,或响应的function?

 var callback = function(data) { if (isError(data)) { /* do something if there was an error */ } /* other logic here */ }; 

似乎更简单。 我能看到的唯一缺点是函数不能将错误作为实际的预期回报值返回 – 但是我相信这是一个令人难以置信的微不足道的用例。

为什么错误优先模式被认为是标准的?

编辑:执行isError

 var isError = function(obj) { try { return obj instanceof Error; } catch(e) {} return false; }; 

另一个编辑:是否有可能我的替代方法比节点约定更方便,因为只接受一个参数的callback更有可能是非callback用例的可重用?

(请参阅下面的“更新”以便npm模块使用问题中的callback约定。)

这只是一个惯例。 节点可以使用你所build议的惯例 – 除非你注意到,你将无法返回一个错误对象作为成功的预期值,根据你的特定需求,这可能是也可能不是问题。

当前的Node约定是有时callback函数可能不会期望任何数据, err是它们唯一的参数,有时这些函数在成功的时候会期望一个以上的值 – 例如见

 request(url, (err, res, data) => { if (err) { // you have error } else { // you have both res and data } }); 

查看这个答案的完整例子的上述代码。

但是,即使在使用多个参数的函数中,您也可以使第一个参数成为一个错误,即使那样,我也没有发现任何问题。

错误优先的Node-stylecallback是Ryan Dahl最初使用的callback,现在它非常普遍,并且期望任何采用callback的asynchronous函数。 这并不是说这个约定好于你的build议或者更糟,而是一个约定 – 不pipe它是什么 – 使得callback和callback的组合成为可能,像async这样的模块依赖于这个约定。

实际上,我发现你的想法优于经典的Node约定 – 你不可能同时调用错误和定义的第一个非错误参数,这对于Node风格的callback是有可能的,有时也可能发生。 这两个约定可能会有callback调用两次虽然 – 这是一个问题。

但是在JavaScript中还有另外一个广泛使用的约定,特别是Node,它不可能同时定义错误和数据,而且不可能再次调用callback – 而不是callback一个promise,而不是明确地检查if像Node样式的callback或样式callback中的情况一样,可以单独添加成功和失败callback,只获取相关数据。

所有这些风格在他们可以做的事情上都是相当的:

 nodeStyle(params, function (err, data) { if (err) { // error } else { // success } }; yourStyle(params, function (data) { if (isError(data)) { // error } else { // success } }; promiseStyle(params) .then(function (data) { // success }) .catch(function (err) { // error }); 

承诺可能会更方便您的需求,并已得到广泛的支持,使用它们的工具很多,如Bluebird等。

您可以在其中解释callback和承诺之间的差异以及如何更详细地使用这些差异,这在这种情况下可能对您有所帮助:

  • 有关如何使用callback和承诺的详细说明
  • 有关如何在复杂的请求处理程序中使用promise的说明
  • 关于AJAX请求的例子,解释了什么是承诺
  • 混合callback与承诺的例子

当然,我看不出有什么理由不能编写一个模块来将Node风格的callback转换成你的风格的callback,反之亦然,同Promise和asCallback一样在promise中也是如此 。 如果使用你的callback风格对你来说更方便,这当然似乎是可行的。

更新

我刚刚在npm上发布了一个模块,您可以使用它来获得您喜欢的callback风格:

您可以安装它并在您的项目中使用:

 npm install errc --save 

它允许你有这样的代码:

 var errc = require('errc'); var fs = require('fs'); var isError = function(obj) { try { return obj instanceof Error; } catch(e) {} return false; }; var callback = function(data) { if (isError(data)) { console.log('Error:', data.message); } else { console.log('Success:', data); } }; fs.readFile('example.txt', errc(callback)); 

更多示例请参阅:

我写了这个模块作为如何操作函数和callback以满足您的需求的一个例子,但是我在MIT的许可证下发布了它,并在npm上发布,所以如果您愿意的话,您可以在真实的项目中使用它。

这展示了Node的灵活性,它的callback模型以及编写高级函数来创build适合您需求的API的可能性。 我希望它可以作为一个例子来理解Node的callback风格。

因为没有这个约定,开发人员将不得不维护不同的签名和API,而不知道将错误放在参数数组中的位置。

在大多数情况下,可能会有很多争论,但只有一个错误 – 而且您知道在哪里可以find它

Joyent甚至在他们涉及更多的时候写到 :

callback是asynchronous传递事件的最基本的方式。 用户传给你一个函数(callback函数),并在asynchronous操作完成后的某个时候调用它。 通常的模式是callback被调用为callback(err,result),其中只有err和result中的一个是非null,取决于操作是成功还是失败。