題記:搞互聯網的同學也許都知道一個數字——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思想的功勞。但“速度快了”這句話本身,就是對我們團隊工作最好的褒獎,對我們參與開發的團隊成員的最好的鼓勵。抓住產品改版的機會,就是自己對優化的研究和經驗的積累落實到細節的機會。雖然還任重道遠。
聲明:本網部份文章為轉載文章,在每篇文章底部有說明,文章的觀點和立場僅代表作者個人立場,不代表微網立場,若是文章轉載中有侵范您的權益,請發郵件到 493149@qq.com或致電13922854199通知刪除,謝謝!