Javascript NodeJs中回调参数的最佳实践

Javascript NodeJs中回调参数的最佳实践,javascript,node.js,optimization,callback,software-design,Javascript,Node.js,Optimization,Callback,Software Design,背景 我是Node.js中的低级库的维护者。该库的重点是速度,并进行了大量优化。然而,有一个很大的减速:回调参数 问题 回调由库使用者提供,每次扫描可以调用多次。对于每个调用,都会计算所有参数并将其传递给回调。在大多数情况下,回调实际上只使用了一小部分参数 目标 目标是消除这些参数的不必要计算 解决方案理念 理想情况下,NodeJs将公开回调函数定义的回调参数。然而,如果没有大量的黑魔法(字符串解析),获得它们似乎是不可能的。它也不能解决只需要有条件地使用参数的情况 我们可以要求回调公开所需的

背景

我是Node.js中的低级库的维护者。该库的重点是速度,并进行了大量优化。然而,有一个很大的减速:回调参数

问题

回调由库使用者提供,每次扫描可以调用多次。对于每个调用,都会计算所有参数并将其传递给回调。在大多数情况下,回调实际上只使用了一小部分参数

目标

目标是消除这些参数的不必要计算

解决方案理念

  • 理想情况下,NodeJs将公开回调函数定义的回调参数。然而,如果没有大量的黑魔法(字符串解析),获得它们似乎是不可能的。它也不能解决只需要有条件地使用参数的情况
  • 我们可以要求回调公开所需的参数,而不是试图从回调中获取参数。这听起来很不方便,而且容易出错,而且也不会有条件地解决问题
  • 我们可以为每个参数组合引入不同的回调。这听起来是个坏主意
  • 我们可以为每个计算并返回参数值的参数传递一个函数,而不是直接传递参数。在回调中,参数将根据需要被调用。这很难看,但可能是最好的方法
问题

  • 其他库如何解决这个问题
  • 还有什么其他方法可以解决这个问题
这是一个非常基本的设计决策,我正在努力做到这一点


非常感谢您抽出时间!一如既往地感谢

您可以向回调传递一个对象,该对象上有各种方法,使用回调的客户端可以调用这些方法来获取他们实际需要的任何参数。这样,您就有了一个干净的对象接口,只需计算实际请求的必要信息

这种通用的设计模式有时被称为“惰性计算”,您只需要根据需要进行计算。根据要公开的接口类型,可以使用访问器函数或getter

出于性能原因,您可能可以在每次调用回调时重用同一对象,而不是构建新对象(取决于实现的细节)

请注意,您甚至不必将计算所需的所有信息放入对象本身,因为在某些情况下,对象上的方法在进行计算时可以引用您自己的局部上下文和局部范围的变量

然而,有一个很大的减速:回调参数

你真的做过基准测试吗?我怀疑构建参数值的代价有多大。请注意,如果这是一个使用非常频繁的调用,V8可能会将其内联,然后优化掉未使用的参数值

理想情况下,NodeJs将公开回调函数定义的回调参数

其实。但是,如果您确实希望依赖此属性,则应该正确地记录您所做的操作,否则这种魔力可能会导致模糊的bug

我们可以为每个参数组合引入不同的回调。这听起来是个坏主意

提供两个选项,
filter(key,value)
filterDetailed(key,value,context)
似乎不是什么大问题。如果优化真的值得,就像你说的,这是一个低级库,那就去做吧

我们可以为每个计算并返回参数值的参数传递一个函数,而不是直接传递参数。在回调中,参数将根据需要被调用。这很难看,但可能是最好的方法

构造要传递的闭包对象而不是参数也会有一些开销,因此需要对其进行适当的基准测试。这可能不值得


但是,我看到您实际上是在传递一个上下文对象作为参数,在该参数上,计算值作为属性进行访问。在这种情况下,您可以简单地使这些属性获取程序在访问它们时计算值,而不是在构造对象时计算值。

从我看到的情况来看,您的回调只有三个参数?@Bergi不幸没有。第三个参数是一个对象,里面隐藏了很多参数。这是很好的输入!非常感谢。除非有更好的答案,否则稍后将接受此更改。此更改的PR目前正在等待中:再次感谢您的输入!这正是我想要的(1)是的,我找到了!编译和注入使速度降低了约4-8倍。V8是智能的,但不幸的是没有那么智能。(2) 可以访问许多不同的参数,例如,当使用第二个参数时,并不总是需要第一个参数。因此,忽略function.length会有奇怪的行为(正如您所提到的),这在这种情况下不起作用(3)。不幸的是,上下文“隐藏”了更多的参数。所以会有很多cb组合(4),我现在想为所有调用保留一个闭包对象,如@jfriend00所述。这将消除开销