博客 / 詳情

返回

js性能優化之數組模式

首先我們來看看下面這兩段代碼,兩段代碼都是在初始化一個長度為1億的數組,唯一區別是在片段二中,先為最後一項賦值1次,大家覺得會有區別嗎?

代碼一:

const arr1 = [];
for ( let i = 0; i < 100000000; ++i ) {
  arr1[i] = 1;
}

代碼二:

const arr2 = [];
arr2[100000000 - 1] = 1;
for ( let i = 0; i < 100000000; ++i ) {
  arr2[i] = 1;
}

我們來嘗試執行一下:

圖片

可以看到片段二比片段一要耗時多出許多,片段一的耗時是318毫秒,片段二的耗時是1343毫秒,中間僅僅因為片段二先為最後一項賦值了1次。

片段二之所以會多出這部分的耗時,歸根結底是因為v8會以不同的形式去存儲js的數組。

圖片

第一種模式是快速模式,V8對應用c語言的數組來對js的數組進行存儲,具備速度快,緊湊的特點。

第二種模式是字典模式,v8 對應用c語言的哈希表來對js的數組進行存儲,特點是速度慢鬆散。

兩種模式的觸發機制如下:

如果數組從首位到最後一位是緊湊的,中間無空洞;或者預分配給數組的大小,小於10萬,無論中間有沒有空洞,都會進入快速模式。

但是如果預分配給數組的大小,大於等於10萬,且中間有空洞,這樣就會把數組進入字典模式。

我們再回到最開始的例子:

圖片

例子的邏輯是,首先我們定義一個數組,再為數組的最後一位賦1,在這個時候,這個數組已經具備了一定的長度,而且這個長度是大於10萬的,而且這個數組中間是有非常多的空洞,只有最後一位有數字。這就意味着在這段片段裏面執行完之後,數組就會在v8裏面去進入了字典模式,而字典模式的特點是鬆散,而且執行相對比較慢,就會導致前面的一段時間耗時會多出許多,這就是底層的原因。

優化策略:

從0開始連續的初始化數組,以避免數組進入字典模式。

不要預分配一個超大數組 (比如長度大於等於 100000)

刪除數組元素時讓數組保持緊湊,儘可能避免使用 delete。

不要訪問未初始化或已刪除的數組元素。

user avatar micherwa 頭像 nidexiaoxiongruantangna 頭像 lfaith 頭像
3 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.