無(wú)標(biāo)題文章

深入 JavaScript 數(shù)組:進(jìn)化與性能

本文轉(zhuǎn)載自:眾成翻譯
譯者:文藺
鏈接:http://www.zcfy.cc/article/4202
原文:http://voidcanvas.com/javascript-array-evolution-performance

正式開(kāi)始前需要聲明,本文并不是要講解 JavaScript 數(shù)組基礎(chǔ)知識(shí),也不會(huì)涉及語(yǔ)法和使用案例。本文講得更多的是內(nèi)存、優(yōu)化、語(yǔ)法差異、性能、近來(lái)的演進(jìn)。

在使用 JavaScript 前,我對(duì) C、C++、C# 這些已經(jīng)頗為熟悉。與許多 C/C++ 開(kāi)發(fā)者一樣,JavaScript 給我的第一印象并不好。

Array 是主要原因之一。JavaScript 數(shù)組不是連續(xù)(contiguous)的,其實(shí)現(xiàn)類似哈希映射(hash-maps)或字典(dictionaries)。我覺(jué)得這有點(diǎn)像是一門(mén) B 級(jí)語(yǔ)言,數(shù)組實(shí)現(xiàn)根本不恰當(dāng)。自那以后,JavaScript 和我對(duì)它的理解都發(fā)生了變化,很多變化。

為什么說(shuō) JavaScript 數(shù)組不是真正的數(shù)組

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

數(shù)組是一串連續(xù)的內(nèi)存位置,用來(lái)保存某些值。注意重點(diǎn),“連續(xù)”(continuous,或 contiguous),這很重要。

上圖展示了數(shù)組在內(nèi)存中存儲(chǔ)方式。這個(gè)數(shù)組保存了 4 個(gè)元素,每個(gè)元素 4 字節(jié)。加起來(lái)總共占用了 16 字節(jié)的內(nèi)存區(qū)。

假設(shè)我們聲明了 tinyInt arr[4];,分配到的內(nèi)存區(qū)的地址從 1201 開(kāi)始。一旦需要讀取 arr[2],只需要通過(guò)數(shù)學(xué)計(jì)算拿到 arr[2] 的地址即可。計(jì)算 1201 + (2 X 4),直接從 1209 開(kāi)始讀取即可。

JavaScript 中的數(shù)據(jù)是哈希映射,可以使用不同的數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn),如鏈表。所以,如果在 JavaScript 中聲明一個(gè)數(shù)組 var arr = new Array(4),計(jì)算機(jī)將生成類似上圖的結(jié)構(gòu)。如果程序需要讀取 arr[2],則需要從 1201 開(kāi)始遍歷尋址。

以上急速 JavaScript 數(shù)組與真實(shí)數(shù)組的不同之處。顯而易見(jiàn),數(shù)學(xué)計(jì)算比遍歷鏈表快。就長(zhǎng)數(shù)組而言,情況尤其如此。

JavaScript 數(shù)組的進(jìn)化

不知你是否記得我們對(duì)朋友入手的 256MB 內(nèi)存的電腦羨慕得要死的日子?而今天,8GB 內(nèi)存遍地都是。

與此類似,JavaScript 這門(mén)語(yǔ)言也進(jìn)化了不少。從 V8、SpiderMonkey 到 TC39 和與日俱增的 Web 用戶,巨大的努力已經(jīng)使 JavaScript 成為世界級(jí)必需品。一旦有了龐大的用戶基礎(chǔ),性能提升自然是硬需求。

實(shí)際上,現(xiàn)代 JavaScript 引擎是會(huì)給數(shù)組分配連續(xù)內(nèi)存的 —— 如果數(shù)組是同質(zhì)的(所有元素類型相同)。優(yōu)秀的程序員總會(huì)保證數(shù)組同質(zhì),以便 JIT(即時(shí)編譯器)能夠使用 c 編譯器式的計(jì)算方法讀取元素。

不過(guò),一旦你想要在某個(gè)同質(zhì)數(shù)組中插入一個(gè)其他類型的元素,JIT 將解構(gòu)整個(gè)數(shù)組,并按照舊有的方式重新創(chuàng)建。

因此,如果你的代碼寫(xiě)得不太糟,JavaScript Array 對(duì)象在幕后依然保持著真正的數(shù)組形式,這對(duì)現(xiàn)代 JS 開(kāi)發(fā)者來(lái)說(shuō)極為重要。

此外,數(shù)組跟隨 ES2015/ES6 有了更多的演進(jìn)。TC39 決定引入類型化數(shù)組(Typed Arrays),于是我們就有了 ArrayBuffer

ArrayBuffer 提供一塊連續(xù)內(nèi)存供我們隨意操作。然而,直接操作內(nèi)存還是太復(fù)雜、偏底層。于是便有了處理 ArrayBuffer 的視圖(View)。目前已有一些可用視圖,未來(lái)還會(huì)有更多加入。

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

了解更多關(guān)于類型化數(shù)組(Typed Arrays)的知識(shí),請(qǐng)?jiān)L問(wèn) MDN 文檔

高性能、高效率的類型化數(shù)組在 WebGL 之后被引入。WebGL 工作者遇到了極大的性能問(wèn)題,即如何高效處理二進(jìn)制數(shù)據(jù)。另外,你也可以使用 SharedArrayBuffer 在多個(gè) Web Worker 進(jìn)程之間共享數(shù)據(jù),以提升性能。

從簡(jiǎn)單的哈希映射到現(xiàn)在的 SharedArrayBuffer,這相當(dāng)棒吧?

舊式數(shù)組 vs 類型化數(shù)組:性能

前面已經(jīng)討論了 JavaScript 數(shù)組的演進(jìn),現(xiàn)在來(lái)測(cè)試現(xiàn)代數(shù)組到底能給我們帶來(lái)多大收益。下面是我在 Mac 上使用 Node.js 8.4.0 進(jìn)行的一些微型測(cè)試結(jié)果。

舊式數(shù)組:插入

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");

用時(shí):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");

用時(shí):52ms

擦,我看到了什么?舊式數(shù)組和 ArrayBuffer 的性能不相上下?不不不。請(qǐng)記住,前面提到過(guò),現(xiàn)代編譯器已經(jīng)智能化,能夠?qū)⒃仡愋拖嗤膫鹘y(tǒng)數(shù)組在內(nèi)部轉(zhuǎn)換成內(nèi)存連續(xù)的數(shù)組。第一個(gè)例子正是如此。盡管使用了 new Array(LIMIT),數(shù)組實(shí)際依然以現(xiàn)代數(shù)組形式存在。

接著修改第一例子,將數(shù)組改成異構(gòu)型(元素類型不完全一致)的,來(lái)看看是否存在性能差異。

舊式數(shù)組:插入(異構(gòu))

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");

用時(shí):1207ms

改變發(fā)生在第 3 行,添加一條語(yǔ)句,將數(shù)組變?yōu)楫悩?gòu)類型。其余代碼保持不變。性能差異表現(xiàn)出來(lái)了,慢了 22 倍

舊式數(shù)組:讀取

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");

用時(shí):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");

用時(shí):27ms

結(jié)論

類型化數(shù)組的引入是 JavaScript 發(fā)展歷程中的一大步。Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,F(xiàn)loat32Array,F(xiàn)loat64Array,這些是類型化數(shù)組視圖,使用原生字節(jié)序(與本機(jī)相同)。我們還可以使用 DataView 創(chuàng)建自定義視圖窗口。希望未來(lái)會(huì)有更多幫助我們輕松操作 ArrayBuffer 的 DataView 庫(kù)。

JavaScript 數(shù)組的演進(jìn)非常 nice。現(xiàn)在它們速度快、效率高、健壯,在內(nèi)存分配時(shí)也足夠智能。

相關(guān)文章

  1. Is JavaScript really interpreted or compiled language?

  2. Create / filter an array to have only unique elements in it

  3. Object.entries() & Object.values() in EcmaScript2017 (ES8) with examples

  4. import vs require – ESM & commonJs module differences

  5. A deep dive into ember routers – Ember.js Tutorial part 5

  6. Myths and Facts of JavaScript

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容

  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,265評(píng)論 0 4
  • 【2017年最新】? iOS面試題及答案 設(shè)計(jì)模式是什么? 你知道哪些設(shè)計(jì)模式,并簡(jiǎn)要敘述? 設(shè)計(jì)模式是一種編碼經(jīng)...
    紫色冰雨閱讀 621評(píng)論 0 1
  • 文章來(lái)源: http://www.w3cplus.com/javascript/array-part-1.html...
    akreturn閱讀 403評(píng)論 0 0
  • http://blog.csdn.net/david21984/article/details/57451917 ...
    紫色冰雨閱讀 574評(píng)論 0 0
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,757評(píng)論 0 9