为什么Underscore.js的chain()方法不是懒惰的?

时间:2013-07-17 11:33:05

标签: javascript performance linq underscore.js

根据Underscore.JS来源(https://github.com/jashkenas/underscore/blob/master/underscore.js):

// Start chaining a wrapped Underscore object.
chain: function() {
  this._chain = true;
  return this;
},

// Extracts the result from a wrapped and chained object.
value: function() {
  return this._wrapped;
}

chain()和value()函数只是Underscore对象的简单包装器。

所以,如果我使用以下构造:

_.chain(someCollection)
.map(function1)   
.map(function2)
.map(function3)
.value()

Underscore将创建两个中间集合,并将执行三次枚举。

为什么chain()和value()方法没有实现为惰性求值,就像LINQ实现其方法一样?例如,此链可被视为:

_.chain(someCollection)
.map(function(x){
    return function3(function2(function1(x)));
})
.value();

这种实现是否存在JS相关问题?

2 个答案:

答案 0 :(得分:12)

基本上,为了使.chain()以您描述的方式变得懒惰,每个方法需要几乎两个版本。您需要立即响应方法来执行文档所说的内容(返回一个数组),并且您需要执行延迟计算的惰性方法(返回一个期望稍后为每个元素运行的函数)。

实现这一点的一种方法是将所有下划线写为惰性,并将其公开为链式下划线。然后将普通下划线暴露为惰性下划线的包装,调用惰性下划线,立即求值,然后返回结果。有两个主要问题:(1)它需要做更多的工作;(2)它是一个完全相反的架构,要求所有下划线都被编写为懒惰,只是为了支持对链方法的惰性求值。

JSLinq和.NET的LINQ展示了它当然可行,但开发和维护的开发人员时间以及复杂性和错误可能性的增加都是巨大的成本。 Underscore在1,200行代码中提供80种不同实用程序方法的非延迟评估。 JSLinq在7,000行代码中提供了21种不同实用方法的惰性评估。代码更多,功能更少。

有一个权衡。每个开发人员都可以做出自己的决定(只要他们为自己工作)。

答案 1 :(得分:7)

我相信你正在寻找类似Lazy.js的东西:

  

Lazy.js是一个JavaScript实用程序库,类似于Underscore和Lo-Dash,但有一个重要区别:延迟评估(也称为延迟执行)。在许多情况下,这可以转化为卓越的性能,尤其是在处理大型阵列和/或将多个方法“链接”在一起时。对于小数组上的简单情况(mapfilter等),Lazy的性能应与Underscore或Lo-Dash类似。

修改:看起来好像也是Lo-Dash may be adding the ability to do lazy evaluation