Lazy.js 类Underscore的JavaScript工具库,利用Nodejs实现惰性求值带来高性能

Lazy.js 类Underscore的JavaScript工具库,利用Nodejs实现惰性求值带来高性能

Lazy.js是类似Underscore或Lo-Dash的JavaScript工具库,但是它有一个非常独特的特性:惰性求值。很多情况下,惰性求值都将带来巨大的性能提升,特别是当处理巨大的数组和连锁使用多个方法的时候。

Lazy.js的网站上展示了与Underscore、Lo-Dash比较的图表:

当数组非常大的时候,对于不需要迭代整个数组的方法,例如indexOf和take,Lazy.js的性能提升更为惊人:

惰性求值的威力

假设我们对包含1000个整数的数组进行一些操作

Underscore 版本,会生成许多巨大的中间数组:

var result = _.chain(array).map(square).map(inc).filter(isEven).take(5).value();

Lazy.js 版本,不会生成中间数组。

var result = Lazy(array).map(square).map(inc).filter(isEven).take(5);

Lazy.js的函数和 Underscore 几乎一模一样,只不过它返回的不是数组,而是带each 方法的序列对象。 它不会生成中间数组,而且只有在调用each方法的时候才产生迭代!

同理,进行字符串处理(惰性地):

var firstFiveLines = Lazy(text).split("\n").take(5);

text很大的时候也没关系,不会生成巨大的数组。

它还能生成无穷数列,把DOM事件封装成序列,等等,等等。

更多请看 GitHub上的 README.md

我把README.md 翻成了中文:

Lazy.js中文文档

Markdown源代码在此,欢迎反馈


6 回复

摘要

本文介绍了Lazy.js,一个类似于Underscore或Lo-Dash的JavaScript工具库,但具有惰性求值的独特特性。惰性求值可以显著提高性能,特别是在处理大型数据集时。通过示例代码,我们将展示Lazy.js如何避免生成不必要的中间数组,并仅在需要时才执行计算。

惰性求值的威力

示例:处理大型整数数组

假设我们有一个包含1000个整数的数组,我们想要对其进行一系列操作,如平方、加1、过滤偶数并取前5个结果。

Underscore 版本

var array = Array.from({length: 1000}, (_, i) => i);

var result = _.chain(array)
    .map(x => x * x)      // 平方
    .map(x => x + 1)      // 加1
    .filter(x => x % 2 === 0)  // 过滤偶数
    .take(5)              // 取前5个
    .value();             // 执行所有操作

在这个例子中,Underscore会生成多个中间数组,这可能会导致内存占用增加和性能下降。

Lazy.js 版本

var Lazy = require('lazy.js');

var array = Array.from({length: 1000}, (_, i) => i);

var result = Lazy(array)
    .map(x => x * x)      // 平方
    .map(x => x + 1)      // 加1
    .filter(x => x % 2 === 0)  // 过滤偶数
    .take(5);             // 取前5个

在Lazy.js版本中,操作只是构建了一个执行链,而不会立即生成中间数组。只有在调用result.toArray()result.each(...)等方法时,实际的计算才会被执行。

示例:处理大型文本

如果我们要从一个非常大的文本文件中提取前5行,Lazy.js同样可以提供更好的性能:

var text = `...`;  // 假设这是一个非常大的文本

var firstFiveLines = Lazy(text.split("\n"))
    .take(5)
    .toArray();     // 将结果转换为数组

在这个例子中,Lazy.js不会一次性生成包含所有行的数组,而是逐步读取并处理文本。

总结

Lazy.js通过惰性求值的方式,显著提高了处理大型数据集时的性能。通过避免生成不必要的中间数组,Lazy.js使得数据处理更加高效。更多关于Lazy.js的详细信息可以在其GitHub仓库中找到,包括详细的API文档和示例代码。


不太看好~ 尤其是 ES6 的 generatorsiterators 普及之后!

目前来说 lodash 足矣。

在用lodash

Lazy.js 是一个类似于 Underscore 或 Lo-Dash 的 JavaScript 工具库,它特别之处在于支持惰性求值(lazy evaluation),这在处理大型数据集时能显著提高性能。惰性求值意味着直到必要时才执行计算,从而避免了不必要的中间结果生成。

示例代码

假设我们有一个包含 1000 个整数的数组,并需要对其进行一系列操作:

const Lazy = require('lazy.js');

// 使用 Underscore 进行处理
const array = Array.from({ length: 1000 }, (_, i) => i);

const underscoreResult = _.chain(array)
  .map(x => x * x) // 平方
  .map(x => x + 1) // 加1
  .filter(x => x % 2 === 0) // 只保留偶数
  .take(5) // 取前五个元素
  .value();

console.log(underscoreResult); // 打印结果

// 使用 Lazy.js 进行处理
const lazyResult = Lazy(array)
  .map(x => x * x)
  .map(x => x + 1)
  .filter(x => x % 2 === 0)
  .take(5)
  .toArray(); // 转换为数组

console.log(lazyResult); // 打印结果

解释

  1. Underscore:

    • _.chain(array) 开始一个链式操作。
    • .map(...).filter(...) 会立即生成中间数组。
    • .take(5).value() 执行最终的取值操作。
  2. Lazy.js:

    • Lazy(array) 创建一个惰性序列。
    • .map(...).filter(...) 不会立即执行,而是延迟到 .toArray() 被调用时。
    • .toArray() 强制执行所有操作并返回最终结果。

由于 Lazy.js 的惰性求值特性,它避免了生成大量的中间数组,从而在处理大数据集时更加高效。

回到顶部