Servlet 3.0筆記之異步請求Facebook BigPipe簡單模型實現
當前的前端技術明星為Facebook,相繼拋出了Quickling,BigPipe等新鮮概念,引領著前端優化的潮流。果然具有大公司的范兒,適時的回饋給整個開發社群,讓全體朝前前進了一小步。超贊!
抽空學習了BigPipe,大概相當于分段刷新(flush),強制輸出。雖有點舊瓶裝新酒的味道,不過前端已經進入了細節為王的階段,或許在國內已經有人在用,但缺乏分享溝通,或者還不成熟,缺乏關注,缺少重要數據用以論證等。
BigPipe:高性能的“流水線技術”網頁,或許可以為需要認知的人們打開一扇窗戶。
原文介紹BigPiple:
BigPipe是一個重新設計的基礎動態網頁服務體系。大體思路是,分解網頁成叫做Pagelets的小塊,然后通過Web服務器和瀏覽器建立管道并管理他們在不同階段的運行。這是類似于大多數現代微處理器的流水線執行過程:多重指令管線通過不同的處理器執行單元,以達到性能的最佳。雖然BigPipe是對現有的服務網絡基礎過程的重新設計,但它卻不需要改變現有的網絡瀏覽器或服務器,它完全使用PHP和JavaScript來實現。
BigPipe在Facebook應用中的工作流程:
1. 請求解析:Web服務器解析和完整性檢查的HTTP請求。
2. 數據獲取:Web服務器從存儲層獲取數據。
3. 標記生成:Web服務器生成的響應的HTML標記。
4. 網絡傳輸:響應從Web服務器傳送到瀏覽器。
5. CSS的下載:瀏覽器下載網頁的CSS的要求。
6. DOM樹結構和CSS樣式:瀏覽器構造的DOM文檔樹,然后應用它的CSS規則。
7. JavaScript中下載:瀏覽器下載網頁中JavaScript引用的資源。
8. JavaScript執行:瀏覽器的網頁執行JavaScript代碼。
其帶來效果較為明顯處在于:
這種高度并行系統的最終結果是,多個Pagelets的不同執行階段同時進行。例如,瀏覽器可以正在下載三個Pagelets CSS的資源,同時已經顯示另一Pagelet內容,與此同時,服務器也在生成新的Pagelet。從用戶的角度來看,頁面是逐步呈現的。最開始的網頁內容會更快的顯示,這大大減少了用戶的對頁面延時的感知。如果您要自己親眼看到區別,你可以嘗試以下連接: 傳統模式和BigPipe。第一個鏈接是傳統模式單一模式顯示頁面。第二個鏈接是BigPipe管道模式的頁面。如果您的瀏覽器版本比較老,網速也很慢,瀏覽器緩存不佳,哪么兩頁之間的加截時間差別將更加明顯。
值得一提的是BigPipe是從微處理器的流水線中得到啟發。然而,他們的流水線過程之間存在一些差異。例如,雖然大多數階段BigPipe只能操作一次Pagelet,但有時多個Pagelets的CSS和JavaScript下載卻可以同時運作,這類似于超標量微處理器。BigPipe另一個重要區別是,我們實現了從并行編程引入的“障礙”概念,所有的Pagelets要完成一個特定階段,如多個Pagelet顯示區,它們都可以進行進一步JavaScript下載和執行。
啟用了BigPipe后,服務器端優先輸出頁面整體布局,瀏覽器渲染布局;服務器按照串行方式,一段段按優先級順序,輸出片段內容到瀏覽器端,瀏覽器執行JS函數,同時可能會同時請求新的JS文件(盡可能不要涉及外部JS),下載特定樣式文件(這個時候可以產生并發連接)。瀏覽器渲染頁面單個組件(Pagelet),組件同時加載CSS、JS文件時,不會影響到下一個組件的渲染工作。以往的頁面模型在于,瀏覽器接收所有數據,然后一次性渲染,顯示最終結果給客戶。
BigPipe涉及到的一些問題,原文沒有涉及,來自淘寶的李牧在他的博客中(Facebook讓網站速度提升一倍的BigPipe技術分析)提出一些疑問:
腳本阻滯:
我們知道直接在html中引入外部腳本會造成頁面阻滯,即使使用無阻腳本下載的一系列方法引入外部js,但因為JS單線程,當這些腳本load進來之后運行時也會發生阻滯.因為Facebook頁面多樣,依賴腳本大小不一,這些阻滯會對頁面的快速展現造成影響.
Facebook做法是在ondomready之前只在頭部輸出一個很小的外部腳本,作為bigpipe的支撐.其余所有模塊如果依賴外部腳本(比如某一模塊需要日歷控件支持),都會在domready事件之后加載.這樣做即保證了所有頁面所有模塊都能在domready前快速形成展現,又可以保證無腳本阻滯的快速的domready時間.
最快可交互時間:
domready再快也至少是在頁面第一個使用bigpipe輸出的chunked的http請求完成之后,對于Facebook來說,這很可能是2秒之后了.那在這2s期間,如果只是頁面展現了而不能交互(點擊日歷無反應),那方案依然不夠完美.
Facebook的做法是,在domready后所依賴腳本已被加載之前,點擊行為將會生成一個額外的腳本請求,只將這個點擊所依賴的腳步預先load進來.這樣保證了最快的可交互時間.Facebook在另一篇文章中對這個技術進行了詳細的描述.
Bigpipe原理簡單,實現不復雜,但Facebook卻用了1年的時間才形成完備的解決方案.生成方案需要時間,而解決隨之而來的腳本阻滯,保障最快交互時間等等問題也會消耗大量時間.
較為全面的了解了BigPipe,下面使用使用JAVA Servlet 3.0 異步特性,簡單模擬BigPipe實現,沒有涉及到頁面組件單獨請求的JS、CSS文件等,僅僅用以演示其過程(最終效果大打折扣)。
我們目標頁面大致結構如下,在 The 1KB CSS Grid 生成結構上修改。 

異步Servlet代碼:
傳統MVC模式在這里貌似去除了,一切在服務器端生成,可借助Freemarker或者靜態頁面輔助,減輕純手工拼接HTML代碼的麻煩。
生成客戶端代碼:
![moz-screenshot-3_thumb[1].png (800×441)](http://lh3.ggpht.com/_iP4ZGnOhL6U/TWInkwrtoeI/AAAAAAAAA0I/cG-GT9nK5mo/moz-screenshot-3_thumb[1].png?imgmax=800)
![moz-screenshot-3_thumb[1].png (800×441)](http://lh3.ggpht.com/_iP4ZGnOhL6U/TWInkwrtoeI/AAAAAAAAA0I/cG-GT9nK5mo/moz-screenshot-3_thumb[1].png?imgmax=800)
話說若使用BigPipe,須分段刷新,則服務器無法獲得最終輸出內容長度,只能采用chunked壓縮編碼格式輸出內容,能節省網絡流量;但不利于SEO,按照Facebook做法就是,若搜索爬蟲訪問,就會按照正常方式生成頁面。另一方面,BigPipe的應用場景適合計算量大、較為耗時、擁有若干相互獨立模塊的頁面,中小頁面不太適合。
posted on 2011-02-22 20:47 nieyong 閱讀(2766) 評論(0) 編輯 收藏 所屬分類: Servlet3