在我前面的文章中,有寫到 V8 的內存管理機制,其中 就有 標記整理 算法
但是如果有同學 對js 語言底層的實現 深入瞭解的話,肯定會疑惑,爲什麼需要整理內存,獲得一個大的連續空間呢?
- js 是一個 萬物皆對象的語言,functon,number,string 等等都是對象,就連 Array 都是對象
- 而理論上來說,一個對象是 hash 表結構存儲數據的
- 而hash 表結構存儲數據的話,就意味着 他其實不需要 多麼大的連續空間,就能夠存儲很多很多的數據
所以說,這裏需要更加深入地去了解 V8 內部到底是怎麼處理 一個 對象數據的
1、一個普通的對象內部存儲方式
v8引擎 爲了增加讀取數據的性能考慮,其實做了很多很多的優化
- 在一個普通的對象之中,存放屬性分爲 兩個區域,一個叫做快區域 名字叫做 elements ,一個叫做慢區域 叫做 properties
- 快區域是使用 連續內存進行存儲的,而慢區域則是 使用hash 表結構存儲的
- 當讀取一個屬性的時候,v8 先是在 快區域中尋找,沒找到纔會去 慢區域尋找
- 如下面的內容所示,只要是 數字類型的,就被放在了 elements 裏面,而 其他類型的,被放在了 properties 裏面
- 而數組類型的 ,自然在大多數情況下都被放在了 elements 裏面,也就是說,在 js 裏,其實數組 還真是被放在連續內存裏面的
function FS(fast, slow) {
this.fast2slow = {}
for (let i = 0; i < fast; i ++) {
this[i] = 'fast'
}
for (let i = 0; i < slow; i++) {
this[`slow${i}`] = slow
}
}
var fs = new FS(10, 10)
在某些文章中,有寫到 當 數字大到一定程度的時候,數組 的存儲結構也會變成一個 hash 表
function FS1(fast, slow) {
this.fast2slow = new Array(10)
}
function FS2(fast, slow) {
this.fast2slow = new Array(100000000)
}
var fs1 = new FS1()
var fs2 = new FS2()
- 在 fs1 中,可以很明顯的看到 elements 裏面已經沒有再存儲數據了
- 在 fs2 中,則還有 數據在存儲
2、隱藏類
- 衆所周知的是,js 是一門 動態語言類型,不像 java 語言那樣,有着靜態類型
- 但是 在這方面 就會出現一個問題,那就是讀取數據的時候不如靜態語言快速
- 靜態語言中的 類 會對 某一個屬性 進行規定,然後快速地查找到這個值,而不是像 動態語言一樣,需要遍歷一邊所有的屬性,因爲 V8 引擎不知道 開發者內部到底有沒有這個類
- 那麼爲了這個,V8 引擎爲此又做出了什麼優化呢?
- 在一個對象創建了之後,V8 引擎會爲其分配一個 隱藏類
- 就像是 靜態語言的類一樣,可以幫助 V8引擎 快速地定位到一個元素的所在
- 在類似的數據結構中,V8 引擎會爲其分配相同的類,也就是 相同的屬性名稱,相同的屬性數量
- 有了隱藏類之後,那麼當 V8 訪問某個對象中的某個屬性時,就會先去隱藏類中查找該屬性相對於它的對象的偏移量,有了偏移量和屬性類型,V8 就可以直接去內存中取出對於的屬性值,而不需要經歷一系列的查找過程,那麼這就大大提升了 V8 查找對象的效率
3、優化
所以瞭解了這個之後,又有什麼用呢?
- 使用 typeScript 確實在某種意義上能夠幫助我們加快 js 的運行速度
- 不要隨便地使用 delete 或者 增加一個屬性,因爲這樣會導致 隱藏類失效而 重新 構建一個新的隱藏類
- 使用字面量初始化對象時,要保證屬性的順序是一致的,
- 例如 var a = {x: 1, y: 2}; b = {y: 1, x : 2} 這樣會導致 創建兩個 隱藏類
學習自 李兵 老師的 《圖解 Google V8》
4、其他的優化方案
- 慎用全局變量,因爲會順着作用域鏈查找變量,查找的層級越高,速度就越慢
- 緩存全局變量,例如: 在 一個函數內部,如果需要調用 document.createElement 等函數的時候,先將var doc = document 緩存起來,這樣 doc 就不是全局變量了,而是 在 同一個 作用域中的值
- 通過原型鏈增加方法
- 創建 多個 dom 節點的時候,可以使用 document.createElementFrment 或者 先使用字符串拼接,再一次性 innerhtml
- 使用 字面量的 方法創建一個 數組或者對象,而不是使用 new Object 或者 new Array
- 在數組的循環中 forEach 的 運行速度 > for > for in