只說web前端性能優(yōu)化

---
2015-05-15更新,內(nèi)容越來越多,后續(xù)會把相關(guān)主題拆開來講
---
前段時間在公司內(nèi)部做過一個關(guān)于前端性能優(yōu)化的分享,在這碼起鍵盤來記錄下。
<h2>前提:</h2>
只說前端性能優(yōu)化,涉及到一些具體可用的手段,都是日常工作中比較容易就可以做到的。不涉及復(fù)雜的比如CDN技術(shù),或者服務(wù)器端優(yōu)化技術(shù)(服務(wù)器端優(yōu)化也可以改進(jìn)前端性能)。
分享積累的經(jīng)驗和了解的技巧,因為有時候很多小的改變可以讓用戶體驗有質(zhì)的提升。比如保持一個良好的編碼習(xí)慣和一些簡單但不太注意到的策略。
先講一講一些常見的策略和方案,然后基于一個實際的項目案例來綜合分析并給出解決方案。
(以下文章的截圖圖片都是來自我制作的ppt中)
<h2>問題:</h2>
為什么進(jìn)行前端性能優(yōu)化?

響應(yīng)速度對用戶的影響-用等待時間來衡量.png

可以看出來,前端性能,反應(yīng)給用戶最直觀的方面就是頁面的響應(yīng)速度。
3-5秒還能接受,大于8秒甚至上雙的響應(yīng)時間,作為用戶肯定是接受不了的。
相信我們自己平常上網(wǎng)逛論壇也有類似的體驗。
一句話,頁面的響應(yīng)速度對用戶體驗至關(guān)重要。
<h2>如何提高響應(yīng)速度?</h2>
下面就逐一來講,有的可能沒列舉實例,對細(xì)節(jié)感興趣的朋友可以網(wǎng)上查查相關(guān)主題的資料,或者直接問我。
<h3>1 避免壞請求:</h3>
什么是壞請求?最明顯的就是404請求,也可以把無意義的重復(fù)請求叫做壞請求。
無意義的請求,浪費了服務(wù)器的資源也影響前端性能.jpg

404會導(dǎo)致服務(wù)器無謂的響應(yīng),所以,沒用的請求,比如鏈接圖片,請求無用的資源等都需要及時刪除。
<h3>2 合并js和css文件:</h3>
這樣也可以減少http請求次數(shù)
合并的策略.png

<h3>3 利用緩存:</h3>
可以緩存js css等文件資源,也可以緩存請求回來的數(shù)據(jù)。
開啟了緩存之后,有些資源文件,客戶端就不用每次都從服務(wù)器端重新請求加載,從本地緩存里取,速度會快得多。至于該緩存哪些文件數(shù)據(jù),那就看你的需求了。我們的目的還是想辦法減少請求次數(shù)。
<h3>4 使用css精靈整合圖片:</h3>
通過整合圖片和css定位的方法,我們可以把多張圖片整合到一起,這樣就減少了請求次數(shù)。
<h3>5 啟用壓縮:</h3>
減少請求資源的數(shù)據(jù)量,達(dá)到更快的速度。
<h3>6 避免css @import語句:</h3>
此語句順序加載,會阻塞瀏覽器的并行加載。
<h3>7 優(yōu)化腳本js和樣式表css的順序:</h3>
(經(jīng)測試IE8及以上沒有這個問題,如果還需要兼容IE8以下版本瀏覽器,請注意這點)
<h3>8 處理小文件:</h3>
將小文件比如小的js css文件寫入到html中,或者第二點提到的合并,減少請求次數(shù)。
<h3>9 減少dom數(shù)量:</h3>
想方設(shè)法減少dom數(shù)量,即減少瀏覽器處理的時間,因為很多時候客戶端javascript處理的就是dom,dom的多少直接影響前端到性能,而且是全方位,多角度的影響。
可以想象下,如果web應(yīng)用程序中含有成千上萬的dom節(jié)點,我的意思是比原本多的多多節(jié)點。然后我們需要使用選擇器操作dom,無論如何優(yōu)化,這些dom節(jié)點都是存在的,這無疑是一項耗時的工作。
我見過一個項目,在一個列表下,有2萬多個li節(jié)點(沒錯,是這么多,后面我將會把它當(dāng)作一個實例放最后來講),這些節(jié)點數(shù)據(jù)都是ajax請求回來的,更要命的是,在這些節(jié)點下,還需要完成搜索的功能。
瀏覽器解析dom,渲染樣式都會花費不少時間,何況還需要操作搜索,和各種重繪。
<h3>10 慎用document.write:</h3>
會阻塞瀏覽器的渲染。
<h3>11 使用瀏覽器文檔碎片createDocumentFragment:</h3>
這個可以減少操作dom的次數(shù),從而減少渲染次數(shù),提高頁面性能。
來看個實例,看具體如何運用文檔碎片來改善頁面的性能。
現(xiàn)在假設(shè)頁面中有個列表ul元素,我們需要調(diào)用ajax獲取json數(shù)據(jù)來填充這個列表。
第一個版本代碼:
var list = document.querySelector('ul');
ajaxData.items.forEach(function(item) {
// 創(chuàng)建li元素
var li = document.createElement('li');
li.innerHTML = item.text;
// li元素常規(guī)操作,例如添加class,更改屬性attribute,添加事件監(jiān)聽等
// 迅速將li元素注入父級ul中
list.apppendChild(li);
});
這樣的寫法實際上是非常慢的,因為每一個元素附加到ul元素之上,順帶著瀏覽器處理渲染的過程。我們再來看看使用文檔碎片的寫法如何。
第二個版本代碼 :
var frag = document.createDocumentFragment();
ajaxData.items.forEach(function(item) {
// 創(chuàng)建li元素
var li = document.createElement('li');
li.innerHTML = item.text;
// li元素常規(guī)操作
// 例如添加class,更改屬性attribute,添加事件監(jiān)聽,添加子節(jié)點等
// 將li元素添加到碎片中
frag.appendChild(li);
});
// 最后將所有的列表對象通過DocumentFragment集中注入DOM
document.querySelector('ul').appendChild(frag);
使用文檔碎片處理之后,我們可以分析下附加節(jié)點到ul之上,只需一次就可以,大大減少了瀏覽器處理渲染的過程,節(jié)省了寶貴的時間。
如果沒有事件方面的考慮,或者可以使用事件委托的情況下,甚至可以把節(jié)點都當(dāng)成html來處理,那么我們操作的就都是字符串了,請看第三個版本代碼。
第三個版本代碼:
var htmlStr = '';
ajaxData.items.forEach(function(item) {
// 構(gòu)建包含HTML頁面內(nèi)容的字符串
htmlStr += '<'+'li>' + item.text + '<'+'/li>';
});
// 通過innerHTML設(shè)定ul內(nèi)容
document.querySelector('ul').innerHTML = htmlStr;
當(dāng)然,如果覺得這樣字符串太長,我們可以運用數(shù)組。
第四個版本代碼:
var htmlStr = '';
var htmlArr = [];
ajaxData.items.forEach(function(item) {
// 構(gòu)建包含HTML頁面內(nèi)容的字符串
htmlArr.push('<'+li>' + item.text + '<'+/li>');
});
// 通過innerHTML設(shè)定ul內(nèi)容
htmlStr = htmlArr.join('');
document.querySelector('ul').innerHTML = htmlStr;
<h2>總結(jié)</h2>
那么按這么說,我們就兩招王牌:
減少請求,加快渲染!
提高頁面性能,我們從這兩個點出發(fā),就可以解決很多問題。
以上大都是總結(jié)出來的一些可用的細(xì)節(jié)點。實際上,我們可以通過工具來檢查頁面上可供優(yōu)化的地方,我感覺比較好用的工具是google page speed,大家可以在google應(yīng)用商店搜索安裝,使用方法也很簡單。
除了我在文章中列舉的優(yōu)化外,大家可以參考page speed的說明,查找更多可供優(yōu)化的信息。不過,話說回來,它列舉的不一定都是對的,畢竟我們還是有自己的需求在內(nèi)的。
實際項目中的問題,會表現(xiàn)的更加明顯。
<h2>項目背景:</h2>
企業(yè)內(nèi)部的選擇人員的界面,分集團部門等節(jié)點展示用戶,但是用戶人數(shù)較多就會出現(xiàn)頁面的性能問題,具體表現(xiàn)在:
1 接近3萬人,加載速度50s,前臺的搜索近20s(很多邏輯,支持拼音搜索,模糊搜索等)
2 前臺需要展現(xiàn)的數(shù)據(jù)量太大,造成無響應(yīng)崩潰
結(jié)合以上我們提到的點,我們的解決辦法是:
1 增加單次請求的數(shù)據(jù)量(3萬人,每個人在數(shù)據(jù)庫中都是一條記錄,不可能一次就全部請求加載到web客戶端)。之前每次請求加載500人,來回60次請求,改成每次請求加載3000人,把請求次數(shù)減少到10次左右。這樣一來,對于數(shù)據(jù)的請求加載時間就節(jié)約了6倍多。
2 請求數(shù)據(jù)使用Json,之前是使用xml,然后在前端轉(zhuǎn)換為Json,既浪費轉(zhuǎn)換時間,又需要轉(zhuǎn)換的代碼。這個問題屬于歷史遺留問題,前輩們使用了xml,后來的維護(hù)者就一直這樣了
3 等數(shù)據(jù)請求完成后再調(diào)用angular組件畫地址樹。之前是請求一次就渲染一次地址樹,即請求回來500人地址樹立刻變化(使用的angular,顯示和數(shù)據(jù)是綁定的,數(shù)據(jù)變了顯示就會變)。改成數(shù)據(jù)請求完成之后再統(tǒng)一調(diào)用組件渲染,減少了渲染時間。
4 搜索不使用angular的filter,這個應(yīng)該是angular的bug,每次都是搜索兩次。后來自己寫了實現(xiàn)搜索的方法。
5 最最重要的一點是,3萬人每個人都需要畫一行數(shù)據(jù),造成dom渲染慢。所以每次只畫20人,用戶拖動鼠標(biāo)的時候,再動態(tài)的改變選擇區(qū)的人。這也是利用了angular數(shù)據(jù)和顯示綁定的特點。
想查看原理,請看:
http://twofuckingdevelopers.com/2014/11/angularjs-virtual-list-directive-tutorial
<h2>最后</h2>
雖然現(xiàn)在網(wǎng)絡(luò)速度越來越快,但web前端優(yōu)化還是非常重要,畢竟沒有最快只有更快!我們不能假設(shè)用戶都使用chrome并且網(wǎng)絡(luò)速度都和我們一樣快不是嗎。使用良好的策略,可以讓用戶在有限的帶寬和客戶端硬件資源條件下,獲取最佳體驗!
高效的web應(yīng)用沒有止境。
文章可以隨意轉(zhuǎn)發(fā),但請告知作者,并表明來源。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 圍繞前端的性能多如牛毛,涉及到方方面面,以我我們將圍繞PC瀏覽器和移動端瀏覽器的優(yōu)化策略進(jìn)行羅列注意,是羅列不是展...
    流動碼文閱讀 695評論 0 0
  • 前端開發(fā)面試知識點大綱: HTML&CSS: 對Web標(biāo)準(zhǔn)的理解、瀏覽器內(nèi)核差異、兼容性、hack、CSS基本功:...
    秀才JaneBook閱讀 2,431評論 0 25
  • 這樣的問題,可能每個看書人都會遇到,如果你沒遇到,你一定不是真正喜歡讀書。 有的時候,這個問題并不是別人問你,而是...
    于洛閱讀 444評論 0 2
  • 一直聽說北京西郊鳳凰嶺上的龍泉寺是個“神奇”的地方。 神奇之一在于寺里據(jù)說有相當(dāng)多北大清華的博士,在學(xué)習(xí)達(dá)到一定程...
    廷婷閱讀 986評論 0 51