边城

immutable.js 比原生 JavaScript 快得多

原文链接: blog.klipse.tech

Immutable.js是一个为 JavaScript 提供不可变集合的库,其灵感来源于 Clojure[脚本] 的不可变数据结构。它由 Facebook 开发。

他们在网站上解释如下:

不可变数据一旦创建就不可以更改,这使应用开发变得简单,不需要保护性复制,带来了先进的存储,以及通过简单逻辑就可以检测变化的技术。

持久化数据提供了一个可变的 API,它不会更新原有的数据,而是产生新的变更后的数据。

本文中我们会讲到在一个常见情形中,immutable.jsjavascript会快得多:不修改原数组的情况下向数组添加元素。

javascript中要做这件事情,唯一的方法是先拷贝一个数组,再向其中添加元素。而immutable.jspush的返回一个添加了新元素的新列表;而且,这非常快。

Fast

不可变列表对决 JavaScript 数组

首先,在浏览器中加载immutable.js

Object.keys(Immutable)

这里有一个计算代码执行时间的benchmark函数:

function benchmark(iterations, f) {
var start = new Date();
for (var i = 0; i < iterations; i++) {
f();
}
var end = new Date();
return "Elapsed time: " + (end - start) + " msec";
}
benchmark(1000000, function() {});

顺便提一下,你能看到javascript函数调用机制超级快。

这个页面中所有代码片段均由klipse 插件提供对环境交互的支持。

  1. 环境:代码在浏览器中执行

  2. 交互:你可以修改代码,它会按你的输入执行

现在我们比较一下性能:

  1. 创建一个javascript数组,与创建一个不可变列表之间的对比

  2. 拷贝并在javascript数组中插入元素,与向immutable.js列表中插入元素的对比

创建集合

创建大小为100000javascipt数组几乎不花时间:

benchmark(1, function() {
var jsArr = [];
jsArr[100000] = 42;
});

而创建大小为100000immutable.js列表花了一点时间:

benchmark(1, function() {
      immutableList = Immutable.Range(0,100000).toList();
})

JavaScript 数组的 slice 访求很慢

使用slicepush来操作javascript数组代价很高

var jsArr = [];
jsArr[100000] = 42;
benchmark(100,  function() {
    jsArr.slice(0).push(43);
})

说明:

  1. slice(0)等价于拷贝整个数组

  2. push会修改调用它个方法的数组

    myArr = []; myArr.push(42); myArr.push(43); myArr

不可变的 push 超级快

immutable列表中添加元素非常快:

immutableList = Immutable.Range(0, 100000).toList();

benchmark(100, function() {
          immutableList.push(43);
})

如果你看到花费的时间是0 msec,请相信这不是一个BUG:它真地很快。增加到10倍的迭代次数来看看效果。

在我的计算机上,immutable.jspush比原生javascriptpush快约 100 倍。

注意,在往immutable.js列表中添加元素时,列表本身并未改变。返回的是一个添加了元素的新列表:不可变集合就是这么运作的。

myList = Immutable.Range(0, 10).toList(); 
myList.push(42);
myList.size

深入

这里有一些有意思的文章,详细描述了一些不可变数据结构的用例和实例细节: