前端性能優化四:現代瀏覽器javascript性能優化-js引擎是如何對原型鏈進行性能優化

前端性能優化一:性能指標javascript

前端性能優化二:現代瀏覽器javascript性能優化(1)前端

前端性能優化三:現代瀏覽器javascript性能優化-ICsjava

前言

前面一章咱們已經介紹過js引擎是如何經過shape和ICs來優化js對象。若是沒看過的同窗能夠先看前面一章。這一章介紹一下js引擎是如何對原型鏈進行優化的。web

js引擎對原型鏈性能優化

咱們都知道js是基於原型鏈的編程語言,全部的方法都是經過原型鏈進行共享的。編程

function Bar(x) {
	this.x = x;
}

Bar.prototype.getX = function getX() {
	return this.x;
};

const foo = new Bar(true);
複製代碼

在js中原型對象就是一個普通的js對象,由於原型對象就是一個普通的js對象,因此原型對象有一個屬於本身的shape對象,這個shape比較特殊,原型對象的shape對象沒法共享.瀏覽器

原型鏈存取

當咱們建立一個對象的實例的時候在內存中會發生什麼咱們已經知道了,那當咱們須要使用getX方法的時候會發生什麼呢緩存

  1. 首先檢查foo對象的shape看是否有getX方法,沒有包含getX方法。
  2. 找到Bar.prototype,檢查他的的shape,有getX方法。 也就是一個簡單的讀取須要進行1+2N(N表示找到方法須要的原型鏈的個數)次查找,1次本身自己的shape,不存在找到原型,而後在檢查原型的shape。
    3次檢查在這裏看起來彷佛能夠接受,可是當咱們操做DOM元素的時候const anchor = document.createElement('a'); DOM有6層的原型鏈。

一個最簡單的getAttribute方法就須要經過3層原型鏈在 Element.prototype上才能找到,也就是說根據前面的1+2N公式,須要7次的查找。由於DOM操做在web上是很是常見的操做,那麼這樣的查找是很是的不高效的。

回到前面的例子foo.getX,若是咱們能把原型的查找的和方法的查找包裹在一塊兒作就行了。js引擎經過把原型鏈的指針從實例自己轉移到他的shape上實現了這一操做性能優化

將prototype的指針移到shape上意味着原來的查找操做從1+2N變成了1+N,可是隻要你換了foo的原型,shape就要對應的進行shape變遷。 即便是減小了開銷,可是這個仍然是一個線性的增長,若是查找的原型鏈太深仍是會有不小的性能開銷。

ValidityCell

以前提到,prototype的shape沒法和別的對象共享,就是由於每一個prototype的shape有一個特殊的ValidityCell字段。這個ValidityCell字段標識了是否有人修改了原型對象。同時爲了讓查找更快js引擎也加入了inline cache。前端性能

當第一次運行代碼的時候,inline cache會分別給這幾個字段緩存上數據

  1. prototype:會記錄在哪一個原型對象中找到了須要的字段,這裏是getX方法在Bar.prototype
  2. offset:會記錄找到這個字段的原型中字段的索引
  3. shape:會用來記錄對象實例的shape
  4. ValidityCell:用來記錄當前實例shape指向的原型對象,這裏也是Bar.prototype 在下一次運行這個方法的時候,js引擎會先對比shape是否是同一個和檢查ValidityCell是否爲true,也就是原型對象有沒有更修改過,若是驗證經過,js引擎就能夠直接使用offset,省去不少查找的性能消耗。

可是若是你修改了原型對象,好比delete Bar.prototype.getX在原型對象上刪掉了getX方法。這個時候原型的shape對象會被從新分配,ValidityCell也會變成false,當下一次使用inline cache的時候也通不過檢查從而得不到offset的緩存了,這會影響性能。編程語言

回到以前那個DOM元素的例子,任何對原型鏈的修改都會將ValidityCell設置爲false,若是你修改了Object.prototype,不僅有Object.prototype的shape的ValidityCell變成了false,全部「繼承」他的原型對象的ValidityCell所有都變成了false。也就是說修改Object.prototype了之後會對程序的性能形成很大的影響,由於全部的對象最終都"繼承"Object

總結

以前一章咱們介紹了shape和ICs,這一張咱們又介紹了prototype的shape對象,基於這些知識咱們知道了一個技巧能夠提升咱們的性能:不要修改原型對象,若是你真的須要修改原型對象,請在其餘代碼執行以前就將原型對象修改好。

相關文章
相關標籤/搜索