JavaScript 数组的进化与性能分析


Posted in Javascript onSeptember 18, 2017

正式开始前需要声明,本文并不是要讲解 JavaScript 数组基础知识,也不会涉及语法和使用案例。本文讲得更多的是内存、优化、语法差异、性能、近来的演进。

在使用 JavaScript 前,我对 C、C++、C# 这些已经颇为熟悉。与许多 C/C++ 开发者一样,JavaScript 给我的第一印象并不好。

Array 是主要原因之一。JavaScript 数组不是连续(contiguous)的,其实现类似哈希映射(hash-maps)或字典(dictionaries)。我觉得这有点像是一门 B 级语言,数组实现根本不恰当。自那以后,JavaScript 和我对它的理解都发生了变化,很多变化。

为什么说 JavaScript 数组不是真正的数组

在聊 JavaScript 之前,先讲讲 Array 是什么。

数组是一串连续的内存位置,用来保存某些值。注意重点,“连续”(continuous,或 contiguous),这很重要。

JavaScript 数组的进化与性能分析

上图展示了数组在内存中存储方式。这个数组保存了 4 个元素,每个元素 4 字节。加起来总共占用了 16 字节的内存区。

假设我们声明了 tinyInt arr[4];,分配到的内存区的地址从 1201 开始。一旦需要读取 arr[2],只需要通过数学计算拿到 arr[2] 的地址即可。计算 1201 + (2 X 4),直接从 1209 开始读取即可。

JavaScript 数组的进化与性能分析

JavaScript 中的数据是哈希映射,可以使用不同的数据结构来实现,如链表。所以,如果在 JavaScript 中声明一个数组 var arr = new Array(4),计算机将生成类似上图的结构。如果程序需要读取 arr[2],则需要从 1201 开始遍历寻址。

以上急速 JavaScript 数组与真实数组的不同之处。显而易见,数学计算比遍历链表快。就长数组而言,情况尤其如此。

JavaScript 数组的进化

不知你是否记得我们对朋友入手的 256MB 内存的电脑羡慕得要死的日子?而今天,8GB 内存遍地都是。

与此类似,JavaScript 这门语言也进化了不少。从 V8、SpiderMonkey 到 TC39 和与日俱增的 Web 用户,巨大的努力已经使 JavaScript 成为世界级必需品。一旦有了庞大的用户基础,性能提升自然是硬需求。

实际上,现代 JavaScript 引擎是会给数组分配连续内存的 —— 如果数组是同质的(所有元素类型相同)。优秀的程序员总会保证数组同质,以便 JIT(即时编译器)能够使用 c 编译器式的计算方法读取元素。

不过,一旦你想要在某个同质数组中插入一个其他类型的元素,JIT 将解构整个数组,并按照旧有的方式重新创建。

因此,如果你的代码写得不太糟,JavaScript Array 对象在幕后依然保持着真正的数组形式,这对现代 JS 开发者来说极为重要。

此外,数组跟随 ES2015/ES6 有了更多的演进。TC39 决定引入类型化数组(Typed Arrays),于是我们就有了 ArrayBuffer。

ArrayBuffer 提供一块连续内存供我们随意操作。然而,直接操作内存还是太复杂、偏底层。于是便有了处理 ArrayBuffer 的视图(View)。目前已有一些可用视图,未来还会有更多加入。

var buffer = new ArrayBuffer(8);
var view  = new Int32Array(buffer);
view[0] = 100;

了解更多关于类型化数组(Typed Arrays)的知识,请访问 MDN 文档。

高性能、高效率的类型化数组在 WebGL 之后被引入。WebGL 工作者遇到了极大的性能问题,即如何高效处理二进制数据。另外,你也可以使用 SharedArrayBuffer 在多个 Web Worker 进程之间共享数据,以提升性能。

从简单的哈希映射到现在的 SharedArrayBuffer,这相当棒吧?

旧式数组 vs 类型化数组:性能

前面已经讨论了 JavaScript 数组的演进,现在来测试现代数组到底能给我们带来多大收益。下面是我在 Mac 上使用 Node.js 8.4.0 进行的一些微型测试结果。

旧式数组:插入

var LIMIT = 10000000;
var arr = new Array(LIMIT);
console.time("Array insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.timeEnd("Array insertion time");

用时:55ms

Typed Array:插入
var LIMIT = 10000000;
var buffer = new ArrayBuffer(LIMIT * 4);
var arr = new Int32Array(buffer);
console.time("ArrayBuffer insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.timeEnd("ArrayBuffer insertion time");

用时:52ms

擦,我看到了什么?旧式数组和 ArrayBuffer 的性能不相上下?不不不。请记住,前面提到过,现代编译器已经智能化,能够将元素类型相同的传统数组在内部转换成内存连续的数组。第一个例子正是如此。尽管使用了 new Array(LIMIT),数组实际依然以现代数组形式存在。

接着修改第一例子,将数组改成异构型(元素类型不完全一致)的,来看看是否存在性能差异。

旧式数组:插入(异构)
var LIMIT = 10000000;
var arr = new Array(LIMIT);
arr.push({a: 22});
console.time("Array insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.timeEnd("Array insertion time");

用时:1207ms

改变发生在第 3 行,添加一条语句,将数组变为异构类型。其余代码保持不变。性能差异表现出来了,慢了 22 倍。

旧式数组:读取

var LIMIT = 10000000;
var arr = new Array(LIMIT);
arr.push({a: 22});
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
var p;
console.time("Array read time");
for (var i = 0; i < LIMIT; i++) {
//arr[i] = i;
p = arr[i];
}
console.timeEnd("Array read time");

用时:196ms

Typed Array:读取
var LIMIT = 10000000;
var buffer = new ArrayBuffer(LIMIT * 4);
var arr = new Int32Array(buffer);
console.time("ArrayBuffer insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.time("ArrayBuffer read time");
for (var i = 0; i < LIMIT; i++) {
var p = arr[i];
}
console.timeEnd("ArrayBuffer read time");

用时:27ms

结论

类型化数组的引入是 JavaScript 发展历程中的一大步。Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,这些是类型化数组视图,使用原生字节序(与本机相同)。我们还可以使用 DataView 创建自定义视图窗口。希望未来会有更多帮助我们轻松操作 ArrayBuffer 的 DataView 库。

JavaScript 数组的演进非常 nice。现在它们速度快、效率高、健壮,在内存分配时也足够智能。

总结

以上所述是小编给大家介绍的JavaScript 数组的进化与性能分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jQuery中Form相关知识汇总
Jan 06 Javascript
Js实现无刷新删除内容
Apr 29 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
Jan 04 Javascript
vue事件修饰符和按键修饰符用法总结
Jul 25 Javascript
vue组件初学_弹射小球(实例讲解)
Sep 06 Javascript
ES6 系列之 WeakMap的使用示例
Aug 06 Javascript
最适应的vue.js的form提交涉及多种插件【推荐】
Aug 27 Javascript
详解微信小程序调用支付接口支付
Apr 28 Javascript
微信小程序如何自定义table组件
Jun 29 Javascript
JavaScript图片旋转效果实现方法详解
Jun 28 Javascript
JS数组转字符串实现方法解析
Sep 04 Javascript
微信小程序APP的事件绑定以及传递参数时的冒泡和捕获
Apr 19 Javascript
JavaScript实现HTML5游戏断线自动重连的方法
Sep 18 #Javascript
Node.JS中快速扫描端口并发现局域网内的Web服务器地址(80)
Sep 18 #Javascript
BetterScroll 在移动端滚动场景的应用
Sep 18 #Javascript
Windows下Node.js安装及环境配置方法
Sep 18 #Javascript
jQuery选择器之子元素选择器详解
Sep 18 #jQuery
JavaScript实现的斑马线表格效果【隔行变色】
Sep 18 #Javascript
js实现可以点击收缩或张开的悬浮窗
Sep 18 #Javascript
You might like
php打造智能化的柱状图程序,用于报表等
2015/06/19 PHP
WordPress中&quot;无法将上传的文件移动至&quot;错误的解决方法
2015/07/01 PHP
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
2010/10/20 Javascript
ajax更新数据后,jquery、jq失效问题
2011/03/16 Javascript
在JavaScript中typeof的用途介绍
2013/04/11 Javascript
JS防止用户多次提交的简单代码
2013/08/01 Javascript
js抽奖实现随机抽奖代码效果
2013/12/02 Javascript
jquery插件validation实现验证身份证号等
2015/06/04 Javascript
jquery实现可旋转可拖拽的文字效果代码
2016/01/27 Javascript
手机端 HTML5使用photoswipe.js仿微信朋友圈图片放大效果
2016/08/25 Javascript
详解vee-validate的使用个人小结
2017/06/07 Javascript
vue项目部署上线遇到的问题及解决方法
2018/06/10 Javascript
解决bootstrap模态框数据缓存的问题方法
2018/08/10 Javascript
Vue页面跳转动画效果的实现方法
2018/09/23 Javascript
JQuery常用选择器功能与用法实例分析
2019/12/23 jQuery
微信小程序实现同时上传多张图片
2020/02/03 Javascript
微信小程序开发(一):服务器获取数据列表渲染操作示例
2020/06/01 Javascript
[01:03:36]Ti4 循环赛第三日DK vs Titan
2014/07/12 DOTA
[46:37]LGD vs TNC 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
python 调用c语言函数的方法
2017/09/29 Python
python中(str,list,tuple)基础知识汇总
2018/02/20 Python
python DataFrame获取行数、列数、索引及第几行第几列的值方法
2018/04/08 Python
Python安装selenium包详细过程
2019/07/23 Python
解决pytorch GPU 计算过程中出现内存耗尽的问题
2019/08/19 Python
Python调用Windows命令打印文件
2020/02/07 Python
python爬虫实现获取下一页代码
2020/03/13 Python
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
通往英国高街的商店橱窗:Down Your High Street
2020/07/19 全球购物
党员干部公开承诺书
2014/03/26 职场文书
信访维稳工作汇报
2014/10/27 职场文书
房地产项目合作意向书
2015/05/08 职场文书
运动会通讯稿200字
2015/07/20 职场文书
关于教师节的广播稿
2015/08/19 职场文书
大队委员竞选稿
2015/11/20 职场文书
怎么禁用Windows 11快照布局? win11不使用快照布局的技巧
2021/11/21 数码科技
MySQL库表太大怎么办? 数据库分库分表项目实践
2022/04/11 MySQL