網頁重構——bigpipe中的頁面構建優化

題記:搞互聯網的同學也許都知道一個數字——4秒,有研究表明,如果一個網站沒有在4秒之內加載完成,用戶就會感到焦躁不愉快,並離開這個網站(數據來自性能測試網站http://gtmetrix.com/)。網站的內容、SEO優化、用戶體驗?哪個更重要呢?在速度面前,也許這些都相對更次要。所以提高網頁效率,是我們在新版微博的第一目標。從四個方面來淺談我們新版微博的優化。

一、HTTP請求數的權衡

1.爲什麼要關心http請求?

當瀏覽器向Web服務器發出請求時,它向服務器傳遞了一個數據塊,也就是請求信息。在用戶打開一個頁面的初初,包括等待時間、請求時間、建立響應時間、渲染時間……,都是消耗在前端的。比如下載圖片、下載樣式表、JavaScript腳本、flash等文件。大家應該都經歷過那個“多圖殺貓”的時代,加載那樣一個網頁會花費大量的時間。減少這些資源文件的請求數將是提高網頁顯示效率的重點。

假設用戶家的網速是10Mbps,10Mbps=10/8=1.25MB/s,那麼他打開一個網頁時,如果網頁文件小於1.25MB,理論上他可以在一秒之內打開網頁。下載網頁的快慢在顯示速度上佔了很大比重,所以,網頁本身體積越小,瀏覽速度就會越快。這就需要產品、交互、設計,從最初就遵循儘量精簡的原則。

現在,就揭開新版微博的面紗,看看微博3.0和新版微博的區別吧。

微博3.0截圖

新版微博截圖

微博3.0是大家熟悉的兩欄結構,總寬爲800px,有一級導航和二級導航、發佈框、feed區、個人簡介區。新版微博是現在最流行的三欄式佈局,總寬950px,除以前的內容一個都不少之外,還整合出了左側導航和右側各種引導和公告。所以從理論上講,雖然內容更豐富了,但新版微博着實比微博3.0的頁面體積大了很多。

2.什麼是bigpipe?

網上有個例子舉得好:在飯館點菜吃的時候,如果點了四個菜,廚師沒有必要把四個菜一起炒好再上來。微博3.0就是這種把所有菜都炒好再上桌的網頁加載模式。所以用戶吃上菜的時候,已經是第5秒了。現在新版微博的bigpipe網頁加載模式,是炒好一個菜先一個菜,用戶可以先吃着,廚師再炒第二個菜。甚至可以幾個菜併發同時炒。所以用戶吃上第一口菜的時間可能是第1秒,比之前提前了很多。

bigpipe模式示意圖

JS工程師把頁面分割成若干個小塊(pagelet),模塊彼此獨立,把html語言轉變爲JS語言,再把CSS通過style的方式加載進這段代碼,而不需要用以往的頭部link css地址的方式取樣式。每個模塊有自己對應的html、CSS、JS,一旦開始運行模塊,就會尋找到對應的CSS,並顯示對應innerHTML內容插入到對應的html元素中,同時渲染出本模塊效果。比如執行到feed區域的id="pl_content_homeFeed"時,樣式表只調用了feed.css。

3.爲什麼新版微博CSS的HTTP請求數不降反增?

通過上面說的這種模式,css被全部link到頭部,是爲了給後臺代碼提供出pagelet所需要的樣式列表。以前微博3.0頭部只link了3個CSS,新版微博首頁頭部卻需要link10多個css。雖然加載文件多了,新版微博CSS加載請求數反而高於v3,看似yslow降級了(這個數據已經不能說明任何問題了)。但實際上新版微博CSS沒有像以往一樣合併起來,而是用一個加載一個,CSS和JS被分配到不同流水線中,模塊的加載變成並行的,先執行完的模塊先顯示出來。所以新版微博CSS渲染的總時間並不超過V3CSS渲染的總時間,速度反而快了很多,減少了視覺等待。

上面這張表格,來自yslow的分析。我們通過把頁面切成細小模塊寫樣式的做法,雖然請求數比以前大了8倍,但總大小上直降20K。

將多個CSS合併的做法固然可以減少請求,但對上億用戶的微博頁面來說,完成合並也許會帶來5%速度的提升。但是如果按bigpipe模式,即使http請求數提高了,但是整體的速度也許是之前的50%。

二、對CSS的優化處理

1.提取公用模塊或公用元素,並反覆調用

如果用戶每次訪問微博首頁時,就重新下載讀取CSS文件。這就會造成給服務器帶來額外壓力且用戶重複讀取耗時。新版微博的做法是,把模塊分爲全局級模塊和頁面級模塊,首頁是全站的核心,所有模塊都是重要且重複性高的,所以首頁的所以模塊都是全局級模塊。首頁所需要的CSS被整理成一個pl列表反饋給工程師,等待處理。而一些非公共的css模塊樣式被單獨寫在屬於本頁面的文件裏,這樣就最大化的節省了文件大小及利用率。這麼做還有一個好處,就是公共模塊樣式被調用過後,會在瀏覽器裏留下緩存。調用最頻繁的模塊,反而樣式被最快的加載進來。

舉個簡單的例子:

.clearfix:after{content: ".";display: block;height: 0;clear: both;visibility: hidden;}

.clearfix {display: inline-block;}

這是一段全局代碼,基本上每個頁面都會用到這個類,我們就沒必要把這句寫在每個網頁的CSS裏面,只把它提取到base.css裏,並方便進行皮膚管理。

又比如,首頁右側欄有個“可能感興趣的活動”類似的模塊都是採用獨立的div容器,這個段落的詳細代碼,如果寫在公用CSS文件裏,肯定就浪費了。

2.儘可能少的使用css images

能通過代碼或字符實現的,就不用圖片去解決。比如“可能感興趣的人”展開氣泡上下三角、返回頂部的箭頭、“更多”後面的»符號等。既減小CSS圖片請求,又不會面臨若干套皮膚升級困難的問題,僅通過對CSS的color、backgroud等屬性的控制,就可以換色了。

可以看看按這個做法之後明顯的優勢,下圖來自yslow的statistics。微博3.0的css image總大小爲970.1K,新版微博的css image總大小爲693.9K,總量直降30%。

微博3.0 statistics

新版微博statistics

3.儘量使用CSS3等新技術

在新版微博裏,我們制定了使用CSS3的原則,即非圖片類的元素效果圖,如圓角、陰影、漸變、半透等效果,可以通過樣式控制,而無需切圖的元素,在得到設計師認可後,不用圖片,只做樣式控制。滿足高級瀏覽器的視覺,ie系列不能顯示的,有原則的放棄。不僅爲速度助力,還在放棄低級瀏覽器的大方向前進一步。

4.鼠標滑上效果改用僞類實現

在逐步放棄ie6的事情上,新版微博已經盡最大的努力做了。爲了保證各瀏覽器的完全兼容,微博3.0以前我們曾經放棄讓CSS實現鼠標滑上效果,而由JS控制。隨着ie6使用率的日益降低,新版微博又一大革新就是重新使用僞類,僅通過CSS就實現的瀏覽器原生效果,不僅計算速度比計算一個JS快得多,也終於放棄了低端的ie6。

舉個評論頁feed區的例子:

CSS代碼如下:

每個單條feed在鼠標滑上時,都會顯示舉報和刪除鏈接。這是交互設計出於對頁面呈現內容的視覺舒適感所做的設計,我們通過對塊元素直接寫僞類,實現這個效果,不需要再通過JS了。ie6呢?就讓它一直襬着去吧。

三、對dom結構的優化處理

1.bigpipe模式重構並優化垃圾代碼

v2從v1來,v3從v2來,在v3不堪重負的時候,新版微博的代碼優化誓在必行了。所以我們並沒有沿用之前的結構和CSS,而是直接推翻v3,重構新版微博。和JS工程師一起搭建的bigpipe模式,把頁面分成細小的塊,每一個模塊對應一個CSS。代碼寫到最優,結構和樣式完全分離,並杜絕內聯調用的方式。下圖示意了我們用模塊配頁面的最終效果,模塊可以被細分爲如此程度。模塊拆的細,複用性被提高。

2.儘量減少代碼體積

由於代碼行數越少體積就越小,所以我們這次想辦法減少網頁代碼的行數。相同或類似的模塊,說服設計師把視覺規範統一。我們只通過對CSS補丁,覆蓋原樣式,並不改變頁面的dom結構,直接降低重複代碼率。舉個例子,“我的首頁”和“我的profile頁”,同樣是有feed區域的,區別是但一個有頭像,一個沒有頭像。只需要一套feed.css代碼,然後在“我的profile頁”獨立的頁面級CSS中,打個去掉頭像的補丁即可。

3.首頁中杜絕Table佈局和iframe

杜絕首頁中出現Table佈局。因爲傳統的table佈局,是把內容全部加載完成後,才渲染樣式,延遲效果嚴重。而iframe頁面框架,是非語義的,即使爲空也會有較大資源消耗,還會阻止頁面的onload。

四、對圖片的優化處理

1.圖片的存儲格式

我們改變了v3的做法,把icon類小圖片或背景類圖片,由以前的gif存儲儘可能多的轉爲png8的存儲,這是個減小圖片體積的好辦法。Png8有gif的所有特點,但是相比gif,png8的優勢是alpha透明和更優的壓縮。png24全透明的圖片,只給支持的瀏覽器使用,ie6在不影響視覺的前提下,改爲gif呈現。我們還會利用的圖片優化工具處理圖片,保證效果但卻降低文件大小。下圖是主鍵類頁面的images文件夾示意圖,除必須獨立的icon外,png類型的圖片比重大得多。這在之前的V3並沒有做到。

2.css sprites

在圖片的拼合方面,我們是持之以恆這麼做的。在v3裏,我們把所有首頁和profile頁裏出現的背景類圖片都拼合到一張大圖上,新版微博比之前高明在,我們把放置文件夾細分。假設我們把公用型放入common,頁面類放入index,換膚類放入skin。把sprites拆分的更細,儘可能在加載首頁時,減少圖片請求數。

3.大圖片、小圖片

對於大背景圖,我們的做法是不分割成小區塊兒的。首先的因爲,原本一個圖片的請求數會變成多個。另外,大約80%以上調用圖片所消耗的時間,是用來檢索緩存和確定鏈接是否有效的阻塞時間。也就是說,如果把一個大圖片,切成若干小圖片,雖然解決了圖片的加載時間,卻花費了更多的阻塞時間。

4.在已知寬高的圖片標籤內,直接指定寬高

Feed區域裏頭像需求是50*50的,所以後臺直接吐出這個尺寸的圖片。在已知寬高的情況的,我們在img標籤中直接指定了height和width參數。因爲如果瀏覽器沒有找到這兩個參數,它需要一邊下載圖片一邊計算大小,首頁有多少條feed就有多少個頭像,瀏覽器需要不斷地調整計算。當瀏覽器知道了height和width參數後,即使圖片暫時無法顯示,頁面上也會預留空位,繼續加載後面的內容。

新版上線後,不少公測用戶的反饋速度變快了,微博瀏覽起來更順暢了。這不是我們頁面重構組的功勞,是整個微博團隊,或者說是bigpipe思想的功勞。但“速度快了”這句話本身,就是對我們團隊工作最好的褒獎,對我們參與開發的團隊成員的最好的鼓勵。抓住產品改版的機會,就是自己對優化的研究和經驗的積累落實到細節的機會。雖然還任重道遠。

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