「注释」作者在本文里没有说明这么一个事实: 目前的版本<code>Lo-Dash v2.4.1</code>并没有引入延迟求值的特性,<code>Lo-Dash 3.0.0-pre</code>中部分方法进行了引入,比如<code>filter()</code>,<code>map()</code>,<code>reverse()</code>。 原文![]()
延迟求值-如何让Lo-Dash再提速x100?延迟求值流水线延迟执行后记
但似乎我错了-还可以让<code>Lo-Dash</code>有明显的提升。只需将关注点从细微的优化转移到算法上来。譬如,在一次循环中我们往往会去优化循环体:
但针对循环体的优化往往很难,很多时候已经到极限了。相反,优化<code>getLength()</code> 函数尽量减少循环次数变得更有意义了。你想啊,这个数值越小,需要循环的<code>10ms</code>就越少。
这便是<code>Lo-Dash</code>实现延迟求值的大致思路。重要的是减少循环次数,而不是每次循环的时间。让我们考察下面的例子:
我们只想取出3个价格低于10元的小球。通常情况下我们先过滤整个数据源,最后从所有小于10的元素里返回前面三个即可。
但这种做法并不优雅。它处理了全部8个数据,但其实只需要处理前面5个我们就能拿到结果了。同样为了得到正确的结果,延迟求值则只处理最少的元素。优化后如下图所示:
一下子就获得了37.5%的性能提升。很容易找出提升X1000+的例子。比如:
延迟求值同时带来了另一个好处,我称之为“流水线”。要旨就是避免产生中间数组,而是对一个元素一次性进行完所有操作。下面用代码说话:
上面看似优雅的写法在原始的<code>Lo-Dash</code>里会转换成下面的样子(直接求值):
当引入了延迟求值后,代码大致就成这样的了:
减少不必要的中间变量多少会带来性能上的提升,特别是在数据源特别巨大,内存又吃紧的情况下。
延迟求值带来的另一个好处是延迟执行。无论何时你写了段链式代码,只有在显式地调用了<code>.value()</code>后才会真正执行。这样一来,在数据源需要异步去拉取的情况下,可以保证我们处理的是最新的数据。
而且这种机制在某些情况下也会提高执行效果。我们可以老早发送一个请求获取数据,然后指定一个精确的时间来执行。