手机版

JavaScript数组的演变和性能分析

时间:2021-09-03 来源:互联网 编辑:宝哥软件园 浏览:

需要在正式开始前申报。本文不打算解释JavaScript数组的基本知识,也不涉及语法和用例。本文更多地讨论了内存、优化、语法差异、性能和最近的发展。

在使用JavaScript之前,我熟悉C、C和C#。和很多C/C开发人员一样,JavaScript给我的第一印象很差。

数组是主要原因之一。JavaScript数组不是连续的,它的实现类似于哈希映射或字典。我觉得这有点像B级语言,数组实现完全不合适。从那以后,JavaScript和我对它的理解发生了很大的变化。

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

在谈论JavaScript之前,我们先来谈谈什么是Array。

数组是一系列用于保存特定值的连续内存位置。注意重点,“连续”(continuous,或连片),这很重要。

上图显示了数组是如何存储在内存中。这个数组包含4个元素,每个元素是4个字节。总的来说,它占用了16个字节的内存区域。

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

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决定引入类型化数组,所以我们有了ArrayBuffer。

ArrayBuffer为我们随意操作提供了连续的记忆。然而,内存的直接操作仍然过于复杂和低级。因此,有一个用于处理数组填充的视图。已经有一些可用的视图,将来还会添加更多。

var buffer=new ArrayBuffer(8);var view=new Int32Array(缓冲区);视图[0]=100;要了解有关类型化数组的更多信息,请访问MDN文档。

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

现在从简单散列映射到SharedArrayBuffer不是很棒吗?

传统阵列与类型化阵列:性能

我们之前已经讨论过JavaScript数组的演变,现在让我们测试一下现代数组能给我们带来多少好处。以下是我使用Node.js 8.4.0在Mac上做的一些微测试结果.

传统数组:插入

var LIMIT=10000000var arr=新数组(LIMIT);console.time('数组插入时间');for(var I=0;i LIMITI){ arr[I]=I;}console.timeEnd('数组插入时间');时间:55毫秒

类型化数组:insert varlimit=1000000var buffer=new ArrayBuffer(LIMIT * 4);var arr=new Int32Array(缓冲区);console.time('ArrayBuffer插入时间');for(var I=0;i LIMITI){ arr[I]=I;}console.timeEnd('ArrayBuffer插入时间');时间:52毫秒

妈的,我看到了什么?传统阵列和ArrayBuffer的性能相当?不,不,不。请记住,如前所述,现代编译器已经变得智能,可以将内部具有相同元素类型的传统数组转换为具有连续内存的数组。这是第一个例子。即使使用了新的数组(LIMIT),该数组实际上也是作为现代数组存在的。

然后修改第一个示例,将数组更改为异类(元素类型不完全一致),看看是否有性能差异。

遗留数组:insert(异类)varlimit=1000000var arr=新数组(LIMIT);arr . push({ a : 22 });console.time('数组插入时间');for(var I=0;i LIMITI){ arr[I]=I;}console.timeEnd('数组插入时间');时间:1207毫秒

更改发生在第3行,添加了一条语句将数组更改为异类类型。代码的其余部分保持不变。显示了性能差异,这要慢22倍。

传统数组:读取

var LIMIT=10000000var arr=新数组(LIMIT);arr . push({ a : 22 });for(var I=0;i LIMITI){ arr[I]=I;} var p;console.time('数组读取时间');for(var I=0;i LIMITI){//arr[I]=I;p=arr[I];}console.timeEnd('数组读取时间');时间:196毫秒

类型化数组:read varlimit=1000000var buffer=new ArrayBuffer(LIMIT * 4);var arr=new Int32Array(缓冲区);console.time('ArrayBuffer插入时间');for(var I=0;i LIMITI){ arr[I]=I;}console.time('ArrayBuffer读取时间');for(var I=0;i LIMITI){ var p=arr[I];}console.timeEnd('ArrayBuffer读取时间');时间:27毫秒

结论

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

JavaScript数组的进化非常不错。现在,它们足够快、高效、健壮、智能,可以分配内存。

摘要

以上是边肖介绍的JavaScript数组的演变和性能分析,希望对大家有所帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

版权声明:JavaScript数组的演变和性能分析是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。