在处理使用Node.js和Bluebird.js的某些项目时,我经常看到以下方法:
function someAsyncOp(arg) {
return somethingAsync(arg).then(function (results) {
return somethingElseAsync(results);
});
}
这是,围绕另一个接受完全相同参数的函数创建一个包装函数/闭包。这似乎可以更清晰地写成:
function someAsyncOp(arg) {
return somethingAsync(arg).then(somethingElseAsync);
}
当我向其他人提出建议时,他们通常喜欢它并切换到它。
但是,有一个重要的警告:如果您正在调用类似object.function
的内容,并且该函数依赖于this
(如console.log
那样),那么{{ 1}}将失去其约束力。你必须this
:
object.function.bind(object)
这似乎有可能不受欢迎, return somethingAsync(arg).then(somethingElseAsync).catch(console.log.bind(console));
电话有点尴尬。你可以通过let-t-always-do-the-closure方法出错。
我似乎无法在谷歌上找到关于此的任何讨论,ESLint似乎没有关于不必要的包装函数的任何内容。我试图找到更多关于它的信息,所以我在这里。我想这是一个我不知道自己不知道的事情。 这是否有名称?(无用的闭包?)还有其他想法或智慧吗?谢谢。
修改:有人会评论.bind
也是多余的,是的,是的,让我们假装它做了一些有用的事情。
答案 0 :(得分:2)
这里的讨论非常简单。如果你的函数可以被promise系统直接调用,那么当promise系统直接调用它的确切参数和this
值时,它的值就是你想要的诺言链中的值,那么无论如何,只需将函数引用直接指定为.then()
处理程序:
somethingAsync(arg).then(somethingElseAsync)
但是,如果您的函数没有设置为直接以这种方式调用,那么您需要一个包装函数或类似.bind()
的函数来修复不匹配并完全按照您的意愿调用您的函数或设置适当的回报值。
真的没有什么比这更重要了。它与在Javascript中的任何地方指定任何回调没有什么不同。如果您的函数已经完全符合回调的规范,那么您可以将该函数名称指定为没有包装器的直接引用。但是,如果你所使用的函数不像回调设计的那样工作,那么你使用包装函数来平滑不匹配。
所有回调函数在传递obj.method
作为回调时都有同样的问题。如果您的.method
期望this
值为obj
,那么您可能需要做一些事情以确保在函数执行之前相应地设置this
值。 .then()
处理程序中的回调与任何其他Javascript / node.js函数(如setTimeout()
或fs.readFile()
或其他将回调作为参数的函数的回调没有什么不同。所以,你提到的问题都不是承诺所特有的。事实上,promises通过回调生存,所以如果你试图通过回调进行方法调用,你将遇到问题,并将对象值适当地传递给方法。
仅供参考,可以对方法进行编码,使它们永久绑定到自己的对象,并且可以作为obj.method
传递,但这只能在您的方法实现中使用,并且还有其他一些权衡。一般来说,有经验的Javascript开发人员使用obj.method.bind(obj)
作为传递参考完全没问题。在代码中看到.bind()
也表示您知道方法中需要正确的obj
值,并且已为此做出了规定。
至于你的一些粗体问题或评论:
这有名字吗?
不是我知道的。从技术上讲,它是“将一个命名引用传递给先前定义的函数作为回调”,但我怀疑这是你可以搜索并找到有用的讨论。
还有其他想法或智慧吗?
由于原因,我不完全确定(虽然在其他地方一直是讨论的主题),Javascript编程风格约定似乎鼓励使用匿名内联回调而不是在别处定义方法或函数然后传递该命名参考(就像你更有可能在许多其他语言中做)。显然,如果您将实际代码放在内联匿名函数中处理回调,那么您提到的问题都不会出现。现在,使用ES6中的箭头函数甚至可以保留内联回调中this
的当前值。我并不是说这是对你的问题的回答,只是对常见的Javascript编码约定的观察。
对于让我们永远做关闭的方法,你不会出错。
正如您似乎已经知道的那样,如果它不需要包装,那么包装它是一种浪费。只有当回调规范与现有的命名函数不匹配时,我才会投票支持包装,并且有理由不修复命名函数以匹配回调规范。