IFC,渲染層與合成層,Hidden_Class,Fiber,Node多進程等

IFC

IFC的行框高度由它包含元素的最高高度來決定。在一個行內格式化上下文中,盒是一個接一個水平放置的,從包含塊的頂部開始,同時這些盒之間的水平margin,border和padding都有效。

  1. 創建一個IFC,用其中一個元素撐開父元素的高度,然後設置其vertical-align:middle,其他行內元素則可以在此父元素下垂直居中。
  2. 當inline-level box寬度大於父容器寬度時會被拆分成多個inline-level box,左邊距對第一個inline-level box生效,右邊距對最後一個inline-level box生效。

渲染層和合成層

首先這兩個產生的條件並不一樣,如abosolute定位並加上z-index:3的元素與abosolute加z-index:5的元素摺疊,這隻會生成新的渲染層,自然5在上,3在下。

合成層需要顯示和隱式合成,前者諸如我們添加transformZ:0,會顯示生成新的合成層,而z-index-5不可能存在於新的合成層下面,所以它也被隱式提升爲了新的合成層。

注意BFC也是生成了新的渲染層,這樣我們就很好的去理解爲什麼BFC可以解決同級邊距摺疊的問題,因爲他們根本不再一個層面上。

V8 Hidden Class

首先,JS作爲動態類型的語言,對象屬性是可以在運行過程中動態的增刪改的,若使用類似字典的數據結構來存儲對象的屬性,相對於靜態類型的語言,動態查找屬性在內存中的位置要慢的很多,爲了提高訪問速度,V8使用動態的創建hidden_class的形式去優化。

一個直白的例子:

function fn(){this.a = a;this.b = b}

當我們new fn() 時,首先會創建一個空的hidden_class,稱爲c0,接着執行到第一條語句時,會在c0的基礎上創建c1,c1代替c0成爲這個對象新的hidden_class,以此類推,最後c2是這個對象的hidden_class。

動態創建hidden_class的行爲看起來很低效,但是當hidden_class可以被反覆利用的時候,這種方式看起來就高效多了。

通知這種方式也是有侷限性的,如如果我們使用delete方法,對象又會倒退回字典查找模式,刪除屬性,並進一步優化,代價很大。

hidden_class還有很多知識,這裏只是九牛一毛罷了。

幾個React常問的問題

首先是事件的bind(this),JSX的語法糖最終會被轉化爲React.createElement方法,最終所有的事件都會被dispatchEvent分發,在這個過程中,函數會被當作參數傳遞,this 是很容易丟失的,React處於性能優化的角度,讓我們手動加 bind。

Fiber,簡單的說是一種單線程時間調度的方法,React遞歸比較虛擬DOM樹並一口氣patch到真實DOM上的過程我們可以看作是一個長進程,而Fiber的作用就是中斷這個過程,將控制權交回瀏覽器,讓位給高優先級的任務,瀏覽器空閒後再恢復渲染,這可能也是Fiber(協程)的由來,因爲和它的思想有些類似。
具體地說,當瀏覽器執行完高優先級的任務後,會分出一片時間塊給React程序執行,當有更高優先級的任務時,React再將權力返回給瀏覽器,這裏使用了超時檢查的機制,如我們常見的16ms。下圖是我們常見的1frame內瀏覽器可以做的事:
在這裏插入圖片描述
React利用了requestIdleCallback,同時對不支持這個API的瀏覽器添加了polyfill。在這個空閒時間內,從根節點開始遍歷 Fiber Node,並在一段時間後交還給瀏覽器。

當然,React也爲了Fiber架構做出了大量的調整,由於之前同步的、遞歸的Stack Reconcilation無法隨意中斷,也很難被恢復,不利於異步處理等特點,React轉而使用了鏈表來模擬棧結構:
在這裏插入圖片描述
同時現在React的每次渲染都分爲了兩個階段,一個是協調,一個是提交,前者可以中斷,後者仍然需要一口氣執行到底(協調和提交是交替進行的)。

上面分類的講述了Fiber,下面我們引用這裏的文章看一下執行過程:

第一部分從 ReactDOM.render() 方法開始,把接收的 React Element 轉換爲 Fiber 節點,併爲其設置優先級,創建 Update,加入到更新隊列,這部分主要是做一些初始數據的準備。

第二部分主要是三個函數:scheduleWork、requestWork、performWork,即安排工作、申請工作、正式工作三部曲,React 16 新增的異步調用的功能則在這部分實現,這部分就是 Schedule 階段,前面介紹的 Cooperative Scheduling 就是在這個階段,只有在這個解決獲取到可執行的時間片,第三部分纔會繼續執行。具體是如何調度的,後面文章再介紹,這是 React 調度的關鍵過程。

第三部分是一個大循環,遍歷所有的 Fiber 節點,通過 Diff 算法計算所有更新工作,產出 EffectList 給到 commit 階段使用,這部分的核心是 beginWork 函數,這部分基本就是 Fiber Reconciler ,包括 reconciliation 和 commit 階段。

Fiber帶來的影響是很大的,包括最新DOM算法的改變,可以見這篇文章,不說了,我去學了。

node多進程

進程與線程的區別,前者是系統調度運行的基本單位,後者是CPU調度運行的基本單位,前者是後者的容器。

Node開啓多進程不是爲了解決高併發,主要是解決了單進程模式下 Node.js CPU 利用率不足的情況,充分利用多核 CPU 的性能。

Nodejs創建多進程的方式主要有cluster和child_process兩種方式。兩者都是以fork一系列的API爲主開闢新的進程,後者更加靈活,前者通過需要通過一個主進程管理多個工作進程,通過循環算法實現負載均衡,能夠更簡單的提高多核的利用率。

創建多進程並不是終點,能夠實現進程間的通信,即IPC纔是真正能夠提升效率的表現,Node中實現IPC通道是依賴於libuv的,父進程在實際創建子進程之前,會創建IPC通道並監聽它,然後才真正的創建出子進程。

想深入瞭解,還是看這篇文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章