YSlow有23條規則,中文能夠參考這裏。這幾十條規則最主要是在作消除或減小沒必要要的網絡延遲,將須要傳輸的數據壓縮至最少。css
1)合併壓縮CSS、JavaScript、圖片,靜態資源CDN緩存html
經過構建工具Gulp,能夠在開發的時候就將合併壓縮的事情一塊兒作掉。node
之因此要作合併壓縮是由於:HTTP 1.x不容許一個鏈接上的多個響應數據交錯到達(多路複用),於是一個響應必須徹底返回後,下一個響應纔會開始傳輸。web
也就是說即便客戶端同時發送了兩個請求,並且CSS資源先準備就緒,服務器也會先發送HTML響應,而後再交付CSS。chrome
使用CDN是爲了讓用戶訪問的時候能用最近的資源,減小來回傳輸時間。設計模式
HTTP2.0改進了HTTP1.x不少方面。瀏覽器
2)CSS放頂部,JavaScript放底部緩存
CSS能夠並行下載,而JavaScript加載以後會形成阻塞。服務器
但凡事仍是會有例外,若是把行內腳本放在樣式表以後,會明顯地延遲資源的下載(結果是樣式表下載完成而且行內腳本執行完畢時,後續資源才能開始下載)。微信
這是由於行內腳本可能含有依賴於樣式表中樣式的代碼,好比document.getElementsByClassName()。
<head> <link rel="stylesheet" href="css/all-normal.css" type="text/css" /> </head> <body> <div id="content"></div> <script> var content = ''; for(i=1; i<1000000; i++) content += '寫入頁面'; document.getElementById('content').innerHTML = content; </script> <img src="images/ui.png" /> </body>
下面經過Chrome的工具查看下:
3)優化DNS解析,減小重定向
在作一個「女神評選活動」的時候,須要在微信中訪問可以獲取用戶的openid,微信獲取用戶基本信息是須要通過幾個步驟的:
先獲取code,再經過code獲取openid,最後再跳轉訪問靜態頁面。
因爲公司將業務分紅了多個小組,因此短短的三步其實須要三個小組配合,須要重定向多個域名。
下圖是未優化前的瀑布圖,但不是最壞狀況,有時候訪問到靜態頁面須要通過10多秒,徹底不能接受,下圖中會跳轉4個域名:
後面不跳index那個域名,直接跳轉到微信操做域名,減小一個域名的跳轉,各小組代碼再作優化,但效果仍是不理想,僅僅快了幾秒。
最後發現實際上是在與微信的服務器作交互的時候,DNS解析花了太多時間!不得已,在服務器的host中添加一條記錄,直接經過IP指向。
下圖是最終優化結果,雖然達不到秒開,但至少能夠接受了:
1)圖片預加載
在作一個「秋名山活動」的時候,使用了圖片預加載。這個活動中有120多張圖片。
流程很簡單,就是答題,最後給評論結果,再分享出去。
若是一會兒加載那麼多圖片,必定是愚蠢的想法,最後決定,在頁面載入的時候先加載一些通用圖片。
在答題的時候當前頁面,預先加載後面頁面中的圖片,防止訪問頁面的時候直接不展現圖片,圖片也作了適當的合併。
將網站地址放在gtmetrix.com測試,下面是最終的瀑布圖,能夠發現圖片都在其餘靜態資源的後面,這樣能儘早的展示頁面給用戶:
優化還遠遠沒有結束,在Chrome中分別模擬了good 2G、good 3G以及4G後,有結果的狀況並不理想。
good 2G:
good 3G:
4G:
還有很大的優化空間能夠作,關於這個預加載的原理,能夠參考《圖片預加載與懶加載》
2)減小分支
在寫業務邏輯的時候,常常會用到if else,switch之類的邏輯判斷,若是每次都作這麼多判斷,很容易影響性能。
因此能夠經過多種方式來避免過多的判斷。
1. 惰性模式
這是在看《JavaScript設計模式》的時候看到的。
減小每次代碼執行時的重複性分支判斷,經過對對象重定義來屏蔽原對象中的分支判斷。
惰性模式分爲兩種:第一種文件加載後當即執行對象方法來重定義,第二種是當第一次使用方法對象時來重定義。
公司有個頁面要提供給第三方APP,可是最終發現第三方APP不能使用localStorage緩存,最終只得作兼容的方式。
但爲了不每次引用方法的時候都作判斷,就使用加載後當即重定義:
var getFn = function() { if (sore.enabled) return sore.get; return cookie.get; }(); var setFn = function() { if (sore.enabled) return sore.set; return cookie.set; }();
2. 創建映射關係
頁面中常常須要彈出框提示,後面就本身作了一個,但彈出框會有不少款式。
若是用簡單工廠模式建立的話,免不了switch分支判斷,後面就直接用賦不一樣的key,還能緩存起來,只初始化一次。
/** * 彈出框單例模式 */ var factories = {}; var DialogFactory = function(type, options) { if (factories[type]) return factories[type]; return factories[type] = new iDialog(options); }; /** * 提示框 */ var Alert = function(content, options) { var d = DialogFactory('alert', options); //其餘邏輯省略 return d; }; /** * 確認框 */ var Confirm = function(content, options) { var d = DialogFactory('confirm', options); //其餘邏輯省略 return d; };
3)第三方代碼異步加載
第三方代碼,例如百度統計、微信SDK等,這些徹底能夠在將業務資源加載完後再添加。
/** * 百度統計設置 */ util.baidu = function(key) { global._hmt = global._hmt || []; (function() { var hm = document.createElement("script"); hm.src = "//hm.baidu.com/hm.js?" + key; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); };
4)cookie與localStorage緩存
有了緩存後,就能減小與服務器的通訊,在本地操做。
公司有個查違章的業務,在本地添加好車輛後,再次進入頁面的時候就須要能直接選擇事先添加好的車輛。
最理想的方式就是添加好後,就在本地緩存起來,下次進入直接調取緩存。
我會優先使用localStorage,下面的表格就是對比:
cookie |
localStorage | |
數據生命週期 |
可設置失效時間 | 除非被清除,不然永久保存 |
數據大 |
大約4KB | 大約5M |
與服務器通訊 |
每次都會攜帶在HTTP頭中,若是使用cookie保存過多數據會帶來性能問題 |
不參與和服務器的通訊 |
本地存儲,以前的歷史大概以下圖所示:
localStorage在瀏覽器兼容方面,IE8竟然也支持了。
5)事件委託
使用事件委託技術能讓你避免對特定的每一個節點添加事件監聽器。
事件監聽器是被添加到它們的父元素上,經過事件冒泡,觸發執行。
在開發的時候,常常會出現動態添加元素的狀況。
若是每次都從新綁定一次事件,那會有不少多餘操做,而綁定在此元素的父級,就只需綁定一次便可。
document.getElementById('ul').onclick = function(e) { var e = e || window.event, tar = e.target || e.srcElement; if (tar.nodeName.toLowerCase() == 'li') { tar.style.background = 'black'; } }
6)節流與去抖動
節流(throttle):預先設定一個執行週期,當調用動做的時刻大於等於執行週期則執行該動做,而後進入下一個新週期。
例如mousemove 事件、window對象的resize和scroll事件。
去抖動(debounce):當調用動做n毫秒後,纔會執行該動做,若在這n毫秒內又調用此動做則將從新計算執行時間。
例如文本輸入keydown 事件,keyup 事件,作autocomplete等。
節流與去抖動最大的不一樣的地方就是在計算最後執行時間的方式上。著名的開源工具庫underscore中有內置了兩個方法。
在作公司內部的一個系統的時候,須要方但願在左右滾動表格的時候,能將第一列固定在最左邊,方便查看。
爲了讓操做能更流暢,我再這裏用了節流,有些瀏覽器會出現卡頓,就得須要增長週期時間。
1)在手機中打印變量
在移動頁面的時候常常須要調試字段,又不能用console.log,每次alert的話,碰到對象就看不到內容了。
只能本身寫個小方法來打印出來,JSON.stringify,經過這個方法可以方便的實現功能。
var print = function(obj, space) { space = space || 4; var html = JSON.stringify(obj, null, space); html = html.replace(/\n/g, '<br>').replace(/\s/g, ' '); var pre = document.createElement('pre'); var div = document.createElement('code'); pre.style.cssText = 'border:1px solid #000;padding:10px;background:#FFF;margin-bottom:20px;'; div.innerHTML = html; pre.appendChild(div); var body = document.querySelector('body'); body.insertBefore(pre, body.children[0]); }; print({a:1, b:'demo', c:{text:'content'}});
2)chrome插件JSON-handle
服務器返回的不少都是JSON格式的數據,一般寫好後給你個接口,順便給你幾個demo參數。
在瀏覽器中打開後,就是一串字符串,但要給人看的話,就得格式化一下了,這個插件就是用來讓人看的。