前端性能調優

前幾天,對九霄項目進行了一次大範圍的性能優化,效果還不錯,首屏從最開始的899個請求4.98s加載,到最後29個請求998ms加載,提高了79%以上。這裏記錄一下優化的過程,方便有須要的朋友。css

開篇

新工做已經4個多月,從0開始到如今三個子系統並行,每一個子系統負責滴滴業務線的數據分析,業務量和業務邏輯至關複雜。不過隨着業務的擴展,性能也隨之會成爲阻礙系統運轉的瓶頸,性能優化勢在必行。html

現狀

目前前端技術架構是:前端

seajs + arale + koa + gulp + lesshtml5

頁面部署是:node

+ router.js
      - entry[入口]
      - express[快車]
      - hitch[順風車]
      - daijia[代駕]

頁面是由路由依次進入四個頁面。因爲是單頁面應用,因此資源文件都是一次加載,致使子系統越多,加載文件越多,網站也愈來愈慢。nginx

優化

優化一: 按需加載

從上面的架構來看,seajs模塊combo在一塊兒,合成一個 nsky.min.js 的原始發佈方案已經不能知足需求了,須要劃分子系統按需加載。git

按需加載的意思是,進入首頁時加載首頁必須依賴的模塊,不加載其餘頁面(快車,順風車,代駕)所需資源。github

seajs請求資源的原理是正則掃描每一個模塊中require的字符串,從而提取模塊的依賴。加載模塊時,首先加載其依賴文件,所以咱們可以經過 combo 的方式把模塊合併到一個文件。另外,seajs中提供 require.async 來實現異步加載。web

所以,咱們在router裏面轉發到不一樣頁面的時候使用 require.async,從而實現分子系統按需加載。express

優化結果以下:

首屏請求數量直接從899個優化到57個,結果仍是可喜。

優化二:請求合併

觀察請求瀑布流,發現請求文件仍是太多,好比系統資源加載(class.js/events.js/overlay.js等),還有業務代碼較多,咱們能夠把這些資源合併在一塊兒,發出combo請求。

好比發出

http://d.kuaidadi.com/path/??class.js,events.js,overlay.js,xxx.js

而後服務端響應此 combo 請求,返回 class.js, events.js, overlay.js, xxx.js的合集,這樣就能夠實現請求合併。

首先,須要瀏覽器發出相似 ??a.js,b.js,c.js 的combo請求。seajs發出combo請求很簡單,經過seajs combo插件就能夠了:

seajs.config({
    preload: "seajs-combo"
 });

其次,須要服務器端響應相似 ??a.js,b.js,c.js 的combo請求。

seajs combo插件中文文檔中提到,服務端實現combo請求是經過Nginx-Http-Concat實現。

可是因爲線上服務器是經過 Nginx 來實現數臺生產機器間負載均衡,經過 Nginx Proxy Pass實現非80端轉發到80端口。通過試驗發現,Nginx的 Proxy PassNginx-Http-Concat不能同時使用,其做者也說過暫時不支持。,因此此路不通。

所以,只能本身實現Node Combo。因而又找了很多node-combo項目(好比node-combo),研究其實現思路,準備本身寫koa-node-combo插件了。

後來搜索npm倉庫,發現有多個這樣的插件,嘗試發現koa-combo-parse可行:

app.use(comboParse({
    base: path.resolve(__dirname, '../client/')
}));

可是,問題又來了。combo到一塊兒後系統仍然不能運行,由於文件之間沒有識別的id。須要尋找工具來對每一個模版補全id和依賴(deps),combo後就能互相識別了。即須要從:

define(function(require, exports, module){
    var a = require('a'),
        b = require('b'); 
    module.exports = {};
});

變成:

define('moduleId', ['a', 'b'], function(require, exports, module){
    var a = require('a'),
        b = require('b');
    module.exports = {};
});

在此過程當中調研了 spmgulp-seajs-combo等,發現都不知足需求。

因而本身實現了node小工具 iddeps,並寫成了gulp插件gulp-ids-deps

最終,前端發出combo請求後,後端響應combo請求,效果以下:

請求數量從57減小到37,請求時間從1.4s減小到了1.18s。

優化三:模版文件預編譯

從上面的瀑布流能看出,tpl文件既大又多,佔用很多請求時間。

在handlebars中,有預編譯的思想,能夠在運行前把模版文件預編譯成爲 js 文件。

業界沒有相應的工具,因而本身寫了一個node小工具tpl-2-js,並改寫成gulp插件gulp-tpl-2-js

Handlebars預編譯的過程是:

//  node
   var preCompileData = handlebars.precompile(data);
// web 
   var Handlebars = require('handlebars'),
    template = Handlebars.template;

   template(preCompileData)({data});

預編譯的過程,是Handlebars precompile建立了一個函數,把每一個template存儲在 Handlebars.templates裏面。

更多詳細請看:gulp-tpl-2-js

通過模版預編譯後、Combo後,效果以下:

能夠看到,請求結果從上次的37減小到29,請求時間從1.18s減小到998ms

後續

總體結果優化的效果差很少了,請求數變到最小,時間首屏時間也符合指望。

後續的優化,能夠考慮經過 html5 的 appcache 緩存不常常的更新資源文件,把 200 的資源文件變成 302。

本文是記錄本身優化系統的心路歷程,有不一樣意見或者有所收穫的能夠留言討論。

原創文章,歡迎轉載。轉載請註明:轉載自Fs21 ' s Home,謝謝!
原文連接地址:前端性能調優

相關文章
相關標籤/搜索