消除 .then 处理程序中不必要的包装函数?
Eliminating unnecessary wrapper functions in `.then` handlers?
我在处理某些使用 Node.js 和 Bluebird.js 的项目时经常看到以下方法:
function someAsyncOp(arg) {
return somethingAsync(arg).then(function (results) {
return somethingElseAsync(results);
});
}
这是围绕另一个接受完全相同参数的函数创建包装器 function/closure。看起来这可以写得更干净:
function someAsyncOp(arg) {
return somethingAsync(arg).then(somethingElseAsync);
}
当我推荐给别人时,他们通常会喜欢并转用它。
但是,有一个重要的警告:如果您正在调用类似 object.function
的函数,并且该函数依赖于 this
(就像 console.log
那样),那么 this
将失去其绑定。你必须做 object.function.bind(object)
:
return somethingAsync(arg).then(somethingElseAsync).catch(console.log.bind(console));
这看起来确实不受欢迎,而且 .bind
调用感觉有点尴尬。让我们始终关闭的方法不会出错。
我似乎无法在 google 上找到任何关于此的讨论,ESLint 中似乎没有关于不必要的包装函数的任何内容。我想了解更多关于它的信息,所以我来了。我想这是我不知道我不知道的情况。 有这个名字吗?(无用的闭包?)还有其他想法或智慧吗?谢谢。
编辑:有人要评论说someAsyncOp
也是多余的,是的,是的,让我们假装它做了一些有用的事情。
这里的讨论非常简单。如果您的函数可以被 promise 系统直接调用,当它被 promise 系统直接调用时,它的 return 值正是您想要的,并且具有确切的参数和 this
值在承诺链中,那么无论如何,只需将函数引用直接指定为 .then()
处理程序:
somethingAsync(arg).then(somethingElseAsync)
但是,如果您的函数没有设置为以这种方式直接调用,那么您需要一个包装函数或类似 .bind()
的东西来修复不匹配并完全按照您的需要或设置调用您的函数设置正确的 return 值。
真的没有比这更多的了。这与在 Javascript 中的任何地方指定任何回调没有什么不同。如果您有一个已经完全符合回调规范的函数,那么您可以将该函数名称指定为不带包装器的直接引用。但是,如果您拥有的函数不能完全按照回调的设计方式工作,那么您可以使用包装函数来消除不匹配。
所有回调函数都存在传递 obj.method
作为回调的相同问题。如果您的 .method
期望 this
值为 obj
,那么您可能需要做一些事情来确保 this
值在您的函数执行之前被相应地设置。 .then()
处理程序中的回调与任何其他 Javascript/node.js 函数(例如 setTimeout()
或 fs.readFile()
或其他将回调作为参数的函数的回调没有什么不同。因此,您提到的两个问题都不是承诺所独有的。 promise 恰好通过回调实现,因此如果您尝试通过回调进行方法调用,您将 运行 陷入对象值正确传递给方法的问题。
仅供参考,可以对方法进行编码,使它们永久绑定到自己的对象并可以作为 obj.method
传递,但这只能在您的方法实现中使用,并且有一些其他的权衡。一般来说,经验丰富的 Javascript 开发人员完全可以使用 obj.method.bind(obj)
作为通过的参考。在代码中看到 .bind()
还表明您知道您需要在方法中使用正确的 obj
值,并且您已经为此做好了准备。
关于您的一些粗体问题或评论:
Is there a name for this?
我不知道。从技术上讲,它是 "passing a named reference to a previously defined function as a callback",但我怀疑您是否可以搜索并找到有用的讨论。
Any other thoughts or wisdoms?
由于某些原因,我不完全确定(虽然在其他地方已经成为讨论的主题),Javascript 编程风格约定似乎鼓励使用匿名内联回调而不是定义方法或函数其他地方,然后传递那个命名的引用(就像你在许多其他语言中更有可能做的那样)。显然,如果您将处理回调的实际代码放在一个内联匿名函数中,那么您提到的两个问题都不会出现。在 ES6 中使用箭头函数现在甚至允许您在内联回调中保留 this
的当前值。我并不是说这是对您问题的回答,只是对常见 Javascript 编码约定的观察。
You can't go wrong with the let's-always-do-the-closure approach.
你似乎已经知道,不需要包装的东西包装起来是一种浪费。仅当回调规范与现有命名函数不匹配并且有理由不修复命名函数以匹配回调规范时,我才会投票赞成包装。
我在处理某些使用 Node.js 和 Bluebird.js 的项目时经常看到以下方法:
function someAsyncOp(arg) {
return somethingAsync(arg).then(function (results) {
return somethingElseAsync(results);
});
}
这是围绕另一个接受完全相同参数的函数创建包装器 function/closure。看起来这可以写得更干净:
function someAsyncOp(arg) {
return somethingAsync(arg).then(somethingElseAsync);
}
当我推荐给别人时,他们通常会喜欢并转用它。
但是,有一个重要的警告:如果您正在调用类似 object.function
的函数,并且该函数依赖于 this
(就像 console.log
那样),那么 this
将失去其绑定。你必须做 object.function.bind(object)
:
return somethingAsync(arg).then(somethingElseAsync).catch(console.log.bind(console));
这看起来确实不受欢迎,而且 .bind
调用感觉有点尴尬。让我们始终关闭的方法不会出错。
我似乎无法在 google 上找到任何关于此的讨论,ESLint 中似乎没有关于不必要的包装函数的任何内容。我想了解更多关于它的信息,所以我来了。我想这是我不知道我不知道的情况。 有这个名字吗?(无用的闭包?)还有其他想法或智慧吗?谢谢。
编辑:有人要评论说someAsyncOp
也是多余的,是的,是的,让我们假装它做了一些有用的事情。
这里的讨论非常简单。如果您的函数可以被 promise 系统直接调用,当它被 promise 系统直接调用时,它的 return 值正是您想要的,并且具有确切的参数和 this
值在承诺链中,那么无论如何,只需将函数引用直接指定为 .then()
处理程序:
somethingAsync(arg).then(somethingElseAsync)
但是,如果您的函数没有设置为以这种方式直接调用,那么您需要一个包装函数或类似 .bind()
的东西来修复不匹配并完全按照您的需要或设置调用您的函数设置正确的 return 值。
真的没有比这更多的了。这与在 Javascript 中的任何地方指定任何回调没有什么不同。如果您有一个已经完全符合回调规范的函数,那么您可以将该函数名称指定为不带包装器的直接引用。但是,如果您拥有的函数不能完全按照回调的设计方式工作,那么您可以使用包装函数来消除不匹配。
所有回调函数都存在传递 obj.method
作为回调的相同问题。如果您的 .method
期望 this
值为 obj
,那么您可能需要做一些事情来确保 this
值在您的函数执行之前被相应地设置。 .then()
处理程序中的回调与任何其他 Javascript/node.js 函数(例如 setTimeout()
或 fs.readFile()
或其他将回调作为参数的函数的回调没有什么不同。因此,您提到的两个问题都不是承诺所独有的。 promise 恰好通过回调实现,因此如果您尝试通过回调进行方法调用,您将 运行 陷入对象值正确传递给方法的问题。
仅供参考,可以对方法进行编码,使它们永久绑定到自己的对象并可以作为 obj.method
传递,但这只能在您的方法实现中使用,并且有一些其他的权衡。一般来说,经验丰富的 Javascript 开发人员完全可以使用 obj.method.bind(obj)
作为通过的参考。在代码中看到 .bind()
还表明您知道您需要在方法中使用正确的 obj
值,并且您已经为此做好了准备。
关于您的一些粗体问题或评论:
Is there a name for this?
我不知道。从技术上讲,它是 "passing a named reference to a previously defined function as a callback",但我怀疑您是否可以搜索并找到有用的讨论。
Any other thoughts or wisdoms?
由于某些原因,我不完全确定(虽然在其他地方已经成为讨论的主题),Javascript 编程风格约定似乎鼓励使用匿名内联回调而不是定义方法或函数其他地方,然后传递那个命名的引用(就像你在许多其他语言中更有可能做的那样)。显然,如果您将处理回调的实际代码放在一个内联匿名函数中,那么您提到的两个问题都不会出现。在 ES6 中使用箭头函数现在甚至允许您在内联回调中保留 this
的当前值。我并不是说这是对您问题的回答,只是对常见 Javascript 编码约定的观察。
You can't go wrong with the let's-always-do-the-closure approach.
你似乎已经知道,不需要包装的东西包装起来是一种浪费。仅当回调规范与现有命名函数不匹配并且有理由不修复命名函数以匹配回调规范时,我才会投票赞成包装。