bigPipe 原理分析
一、什麼是bigPipe?
bigPipe是由facebook提出來的一種動態網頁載入技術。它將網頁分解成稱為pagelets的小塊,然後分塊傳輸到瀏覽器端,進行渲染。它可以有效地提升首屏渲染時間。
為了說清楚什麼是bigPipe,我先需要介紹下目前的常規渲染方式,以及可以進行最佳化的方向。
二、網頁首屏載入方案
注:首屏載入方案指的是在服務端就已經吐出頁面的方案,也就是說有SSR的方案,那些純客戶端渲染的方案不做比較,因為它們沒有首屏要求。
現有的網頁首屏載入方案一般會經過以下階段:
傳送http請求到服務端
服務端接收並分析請求
服務端根據請求從儲存層獲取相關資料,這裡可能會比較耗時,比如如果首頁涉及多個模組(廣告位、推薦、內容列表、使用者資訊、好友列表等)
服務端準備好所有內容,拼接成完整的html文件
傳送回客戶端
客戶端接收完整的html文件
構建dom、cssom, 生成render tree,渲染出指定頁面
如下圖所示:
以上載入方案的缺點是,當2、3、4、5 步在服務端進行的時候,瀏覽器只能是傻傻地等待,做不了任何事情!
而且第3步並行拉取業務資料在某些場景下(模組多,業務場景複雜),是會佔用比較多的時間的。而且只要其中某個模組的資料如果拉取較慢,會拖慢整個首屏的顯示。
更糟糕的情況下,某些模組資料相互依賴,導致需要序列拉取資料,那造成的瀏覽器的等待則會更久。
三、最佳化方案
以上方案在一些服務端渲染頁面中相當常見,不足之處也很明顯。
而bigPipe就是針對第3、4步進行最佳化,讓服務端在準備好某個模組的資料後,立馬返回給客戶端顯示,而不必要等待完整的資料和html生成,再發送給客戶端。
客戶端在接收到某一部分內容後,就可以開始渲染,顯示執行(這裡可以動態請求需要的css,js 等等)。
如下圖,客戶端拉取業務資料和客戶端渲染頁面可以並行。如果某一部分比如廣告資訊拉取超時,也並不影響其他部分率先渲染顯示。
這樣,一個完整的頁面就可以拆成多個部分,分塊渲染,而無需等到拿到完整的頁面返回,再渲染。要知道, 如果要等到完整頁面返回,在這之前,瀏覽器只能是一片空白!
四、關鍵技術和原理
想要實現以上最佳化方案,可以利用現成的技術,所以有比較好的相容性。
1.分段傳輸
bigPipe依賴於分段傳輸html頁面,所以這是實現bigPipe的一個基礎。
http1。1
如果在http1。1版本上實現,那需要設定Transfer-Encoding為chunked,也就是分塊傳輸編碼。
關於分塊傳輸編碼:
分塊傳輸編碼允許伺服器為動態生成的內容維護HTTP持久連線。在這種情況下,不能使用HTTP Content-Length頭來分隔內容和下一個HTTP請求/響應,因為內容大小未知。
分塊編碼的好處是,在返回客戶端前不必生成完整的內容,因為它允許將內容作為分塊進行流式處理,並明確地發出內容結尾的訊號,從而使連線可用於下一個HTTP請求/響應。
在頭部加入 Transfer-Encoding: chunked 之後,就代表這個報文采用了分塊編碼。這時,報文中的實體需要改為用一系列分塊來傳輸。
每個分塊包含十六進位制的長度值和資料,長度值獨佔一行,長度不包括它結尾的 CRLF(\r\n),也不包括分塊資料結尾的 CRLF。
最後一個分塊長度值必須為 0,對應的分塊資料沒有內容,表示實體結束。
http 2
如果你使用的是http2,那則無需設定Transfer-Encoding為chunked,因為http2本身就是支援這種分塊傳輸的協議。
2.瀏覽器渲染原理
說到瀏覽器渲染,我們可以簡單地把它歸為五個階段。(為了方便分析渲染過程,先不考慮有js的情況)
階段一:
解析html文件,生成節點,構建dom樹
階段二:
在階段一中,如果遇到css(內嵌在html文件或者外鏈或者內聯樣式都一樣),則會解析css文件,生成cssom。
階段三:
階段一和階段二都是可以並行的,等到dom和cssom準備好,會進行合併,生成render tree。
階段四:
根據render tree進行layout。
階段五:
繪製到顯示區域。
整個階段如下圖所示
幸運的是,
瀏覽器並不會等解析完完整的html文件後,才進行layout 和paint
。
瀏覽器已經對顯示html文件進行了最佳化,會盡快將解析好的部分呈現給使用者。也就是,上圖所謂的一次渲染過程,在分塊傳輸的時候,是可以多次進行的。直到接收到