沒事使用代理上了下facebook,註冊進入個人首頁後,習慣性的查看原始碼,發現了1個很有意思的現象,首頁內容不少,但原始碼中HTML的代碼卻很少,但去多出了很多段的javascript代碼,這些js代碼都是用於動態產生html的,facebook為什麼需要這樣做了?出於職業習慣,研究研究:
一、html代碼。
先看看首頁查看的原始碼,因為原始碼比較大,所以把圖片壓縮了下,可能看不太清楚,只需要注意圖中紅色是html代碼,其餘黑壓壓一片的就全部是JS代碼:
二、JS代碼
看到黑壓壓的JS代碼是不是被嚇一跳,下面就截取一段JS來分析(其餘段的JS都是類似的),facebook原始碼中充斥了類似於下面的JS代碼:
<script>big_pipe.onPageletArrive({"id":"pagelet_welcome_box","phase":1,"is_last":false,"append":false,"bootloadable":[],"css":["lDRwi","eon+N"],"js":["F+B8D","IdQlc"],"resource_map":[],"requires":[],"provides":[],"onload":["window.__UIControllerRegistry[\"c4c13a3ed2dd1e0e349b72\"] = new UIPagelet(\"c4c13a3ed2dd1e0e349b72\", \"\\\/pagelet\\\/generic.php\\\/WelcomeBoxPagelet\\\/\", {}, {});; ;"],"onafterload":[],"onpagecache":[],"onafterpagecache":[],"refresh_pagelets":[],"invalidate_cache":[],"content":{"pagelet_welcome_box":"<div id=\"c4c13a3ed2dd1e0e349b72\"><div class=\"UIImageBlock clearfix fbxWelcomeBox\"> ...這裡省略N多HTML"},"page_cache":true});</script>
讓我們再看看big_pipe.onPageletArrive函數到底做了什麼了?我們只關注參數中的id,js,css,content4個參數,可以看出js和css都是進行過編碼,下面是解碼後我們關注的代碼:
<script>big_pipe.onPageletArrive({"id":"pagelet_welcome_box","css":{name: "css/c5mv8gd5gwoc4kk0.pkg.css"permanent: truesrc: "http://static.ak.fbcdn.net/rsrc.php/zBP3B/hash/abee68r4.css"type: "css"},"js":{name: "js/19khsprwvtvokwow.pkg.js"permanent: falsesrc: "http://static.ak.fbcdn.net/rsrc.php/zAVXU/hash/e8mwcqsi.js"type: "js"},"content":{"pagelet_welcome_box":"<div id=\"c4c13a3ed2dd1e0e349b72\"><div class=\"UIImageBlock clearfix fbxWelcomeBox\"> ...這裡省略N多HTML"}});</script>
看到還原後的JS,你應該猜出onPageletArrive函數是幹嘛的吧,其實onPageletArrive最主要實現就是把"content"中的html內容插入到對應id(上面的"pagelet_welcome_box")的html元素中,並下載對應的css和JS。
三、chunk、flush
看到上面的分析後,大家一定奇怪,facebook為什麼要產生那麼多段JS,再用js去動態插入html代碼,這不是脫了褲子放屁,多此一舉嗎?還不如直接產生html代碼了。facebook當然不會那麼笨了,讓我們先監控下facebook的http請求,監控圖如下:
注意中紅色部分,原來facebook使用了chunk對頁面進行分塊輸出。這就比較容易理解了,facebook首頁的js程式碼片段不是1次就全部輸出的,而是一段一段進行輸出的。
什麼是chunk和如何使用chunk,請參考我的另1篇博文:flush讓頁面分塊,逐步呈現
總結
facebook使用chunk技術讓頁面分塊輸出成很多JS段,這樣做的好處就是伺服器和用戶端可以並行進行處理,不用等伺服器全部處理完畢,用戶端才進行處理。
舉個部落格園首頁的列子,部落格園首頁分為下面幾塊("推薦部落格排行","首頁隨筆列表","最新新聞"...),
我們一般對該http請求處理如下:
1. 瀏覽器發送http請求
2. 伺服器處理請求(從緩衝讀取前50個推薦部落格,從資料庫讀取"首頁隨筆列表",從資料庫讀取"最新新聞"),產生首頁的html代碼。
3. 伺服器發送html代碼給用戶端
4、瀏覽器接收到響應,處理html(下載css,js,image,執行js等等)
可以看出傳統的http請求4個過程中,每個過程都必須等待前1個過程完成後才能執行,這樣就存在很大的資源浪費。
facebook的對該http請求的處理如下:
1. 瀏覽器發送http請求
2. 伺服器處理請求(從緩衝讀取前50個推薦部落格,產生"推薦部落格"的js程式碼片段,flush輸出該程式碼片段,
伺服器繼續讀取"首頁隨筆列表",並產生輸入js程式碼片段。
伺服器繼續讀取"最新新聞",並產生輸入js程式碼片段。
3. 瀏覽器接收到js程式碼片段,下載該程式碼片段所需的js和css。插入html代碼。
在這個處理流程中,最大的特點就是2,3是並行進行處理的,伺服器處理完一部分資料就把已經處理好的資料交給瀏覽器進行呈現處理,自己再繼續處理其他的資料。
PS:文章看完了,有些同學可能會想,為什麼不像部落格園一樣,前台全部用ajax來非同步讀取"推薦部落格" ,“最新新聞”的資料了,這樣做就不會出現因為要處理太多資料而讓用戶端等待太久的問題了。我覺得對於facebook這種並發量巨大的網站,使用這種方法無疑會產生太多的請求,比如facebook首頁用了14個chunk,如果使用ajax,則需要多14個request請求,這將增加不少伺服器的壓力吧。
相關文章: 名站技術分析 — 淺談tudou.com首頁圖片消極式載入的效果