如今許多公司每每注重後端優化,而忽略了前端優化javascript
想一想若是辛苦優化了服務器,後臺,排查了sql
卻在最後頁面加載展現的時候很慢,也得不償失css
其實,先後臺優化都是相輔相成的
後臺優化好了,響應請求速度快,前臺展現的更迅速
前臺優化了沒必要要的請求,後臺壓力也會更小html
一直想靜下心來寫一篇博文,
無奈心浮氣躁,不得安定,斷斷續續一直寫到今天....
那麼如今就來和你們分享一下個人前端優化經驗吧前端
大綱:html5
請求優化
首先咱們來優化HTTP請求數
因爲用戶瀏覽的,每每只是局部網頁,
因此只加載用戶可視範圍內的資源,就會減小一些沒必要要的請求,也會減小瀏覽器加載資源的消耗
考慮到移動端可視範圍,網絡流量,性能,延遲加載做用尤其明顯
適合延遲加載的東西不少,最須要的固然是圖片,這裏推薦lazyload
https://github.com/tuupola/jquery_lazyload
圖片延遲加載的原理就首先將要延遲加載的圖片src替換爲空白圖片或者參數指定的loading圖
而後根據當前元素的位置(offset)來判斷是否在頁面可視範圍(頁面寬/高度+滾動寬/高度)
若是在,就將真實圖片資源路徑替換回src讓瀏覽器加載
防止瀏覽器解析到HTML中<img>標籤的src屬性就開始下載資源,最好將原<img>的src屬性去掉
統一配置lazyload的參數去加載loading圖吧,如咱們項目中這樣:
$(".main_content img").lazyload({ placeholder: "/images/loading.gif", threshold:200 });
再來看到lazyload的源代碼,可視範圍判斷上下左右,寫的十分完善
$.belowthefold = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop(); } else { fold = $(settings.container).offset().top + $(settings.container).height(); } return fold <= $(element).offset().top - settings.threshold; }; $.rightoffold = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = $window.width() + $window.scrollLeft(); } else { fold = $(settings.container).offset().left + $(settings.container).width(); } return fold <= $(element).offset().left - settings.threshold; }; $.abovethetop = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = $window.scrollTop(); } else { fold = $(settings.container).offset().top; } return fold >= $(element).offset().top + settings.threshold + $(element).height(); }; $.leftofbegin = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = $window.scrollLeft(); } else { fold = $(settings.container).offset().left; } return fold >= $(element).offset().left + settings.threshold + $(element).width(); }; $.inviewport = function(element, settings) { return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) && !$.belowthefold(element, settings) && !$.abovethetop(element, settings); };
關於圖片這裏,除了延遲加載外,用戶上傳的圖片以及咱們所用的資源圖片都應該進行壓縮處理
如須要進一步提升壓縮率,可使用例如:google開發的webp圖片格式等..
不過不是全部瀏覽器都支持webp格式,須要針對瀏覽器響應
根據上面這段代碼,其實咱們就能夠延遲加載其餘內容了,
總之呢,這裏咱們的目的就是儘可能減小沒必要要的請求
好比如今用的不少的下拉式翻頁,就是判斷到頁面底部以後再ajax獲取下頁內容
若是考慮到網頁只是局部更新的話,那使用ajax是很合適的
好處顯而易見,無需從新請求整頁,小巧快速,網頁展現也友好一些
善用ajax對前端性能,體驗都是有改善的
可是也要考慮到對搜索引擎的友好,
若是頁面總體功能改變了,或者頁面改動量大就要進行取捨了。
延遲加載的目的就是減小沒必要要的請求,在用戶有需求時才請求資源
因此對於用戶來講,實際上是有一點點「等待」的過程的
通常會用loading圖,等待文字來改善這裏的用戶體驗
可是有一些需求是但願儘可能少出現這種「等待」過程的
這裏咱們就能夠預加載資源,以下,咱們先在js中加載圖片
var img = new Image(); img.src="test.png";
提早加載好了圖片,用戶進行下一步時,圖片則是從瀏覽器緩存中獲取
多頁數據也能夠相似處理,頁面初始能夠默認加載兩頁數據
翻到第二頁時,就ajax去獲取第三頁內容
翻到第三頁時,就去獲取第四頁內容......
老是提早預加載一頁數據
如此可必定程度上減小一些等待的過程
總的來講延遲加載是儘可能少加載資源,預加載則是判斷可能要的資源,儘可能去提早多加載,
都是爲了優化用戶的體驗,適用於不一樣場景
資源優化
網頁中有些資源能夠經過延遲加載等方式減小沒必要要的請求
而許多的javascript腳本,css樣式等資源倒是網頁中必需要加載的
既然不可避免須要加載,那接着,咱們就能夠去優化這些資源
首先咱們能夠優化資源文件的大小,資源文件變小了,傳輸速度固然也快了
這裏咱們壓縮分爲以下兩種:
以下,在IIS7內啓用Gzip壓縮
能夠看到,設置了以後資源的HTTP響應多了Content-Encoding:gzip
咱們寫js代碼,css,都命名儘可能取得有意義,多換行,tab把格式弄的優美
都是爲了方便維護,再閱讀,而機器解析咱們的代碼的時候可無論這些。
這裏壓縮我推薦 uglify-js和 clean-css,都在nodejs環境下
這裏可見壓縮效果仍是很顯著的,按我目前代碼習慣,平都可以壓縮一半左右
可是,不可避免,咱們在平常開發,發佈的時候,會增長額外的工做量
這裏我分享一下個人用法:
爲了方便開發,我在項目中仍是引用的原文件
只是在生成發佈文件後,執行下面bat批處理腳本
把發佈文件夾內的js代碼進行壓縮,同名覆蓋原文件,這樣就不用修改項目內js引用地址
@echo off :: 設置壓縮JS文件的根目錄,腳本會自動按樹層次查找和壓縮全部的JS SET JSFOLDER=D:\project\scripts echo 正在查找JS文件 chdir /d %JSFOLDER% for /r . %%a in (*.js) do ( @echo 正在壓縮 %%~a ... uglifyjs %%~fa -mangle -o %%~fa ) echo 完成! pause & exit
(*這個bat批處理腳本不是我寫的,是之前在網上搜來的)
固然,用這種bat批處理腳本只知足一些小需求,咱們還能夠用自動化構建工具來生成
這裏我推薦gulp,一樣在nodejs環境下,這裏分享一個我本身寫的靜態資源壓縮生成後綴的gulpjs
裝好gulp以後,須要安裝gulp的插件gulp-clean-css,gulp-uglify,gulp-rev,gulp-rev-collector以及gulp-sync
還有這個gulp-bom,我以前處理完以後,總是有亂碼,發現生成的文件雖然是utf-8 卻不是utf-b+bom,因此須要再處理一下
var gulp = require('gulp'), config = require('./config'), cleancss = require("gulp-clean-css"), uglifyjs = require("gulp-uglify"), rename = require("gulp-rename"), rev = require("gulp-rev"), revCollector = require("gulp-rev-collector"), del = require("del"), sync = require("gulp-sync")(gulp), bom=require("gulp-bom") ; //生成後綴 gulp.task("addv_css", function () { return gulp.src(config.css.src) .pipe(rev()) .pipe(gulp.dest(config.css.dest)) .pipe(rev.manifest()) .pipe(bom()) .pipe(gulp.dest(config.css.rev)); }); gulp.task("addv_js", function () { return gulp.src(config.js.src) .pipe(rev()) .pipe(gulp.dest(config.js.dest)) .pipe(rev.manifest()) .pipe(bom()) .pipe(gulp.dest(config.js.rev)); }); //更改cshtml中的 style引用 gulp.task("changev_css", function () { return gulp.src(config.rev.csssrc) .pipe(revCollector({ replaceReved: true })) .pipe(bom()) .pipe(gulp.dest(config.rev.dest)); }); //更改cshtml中的 js引用 gulp.task("changev_js", function () { return gulp.src(config.rev.jssrc) .pipe(revCollector({ replaceReved: true })) .pipe(bom()) .pipe(gulp.dest(config.rev.dest)); }); //壓縮css gulp.task("cleancss", function () { return gulp.src(config.css.cleansrc) .pipe(cleancss()) .pipe(bom()) .pipe(gulp.dest(config.css.dest)); }); //壓縮js gulp.task("uglify", function () { return gulp.src(config.js.uglifysrc) .pipe(uglifyjs({ mangle: true, define: true })) .pipe(bom()) .pipe(gulp.dest(config.js.dest)); }); gulp.task("default", sync.sync([["addv_css", "addv_js"], "changev_css", "changev_js", ["cleancss", "uglify"]]));
咱們項目內每每會引用多個javascript腳本,和多個css樣式文件
因此能夠把多個腳本合併到一個js文件內,而後統一引用它就能減小http請求
這裏uglify-js和 clean-css 都支持多個文件合併壓縮輸出
>uglifyjs js1.js js2.js -m -o merge.js
>cleancss -o megar.css style1.css style2.css
也能夠在服務器內合併輸出,好比咱們看淘寶的合併:
<script src="//g.alicdn.com/kissy/k/6.2.4/??node-min.js,node-base-min.js,dom-base-min.js,query-selector-base-min.js,dom-extra-min.js,node-event-min.js,event-dom-base-min.js,event-base-min.js,event-dom-extra-min.js,event-gesture-min.js,event-touch-min.js,node-anim-min.js,anim-transition-min.js,anim-base-min.js,promise-min.js,base-min.js,attribute-min.js,event-custom-min.js,json-base-min.js,event-min.js,io-min.js,io-extra-min.js,io-base-min.js,io-form-min.js,cookie-min.js"></script>
他們則是在web服務器內作了處理,請求多個文件,會自動合併
有條件的同窗也能夠這樣進行合併
圖片合併目的也是減小http請求,將頁面中須要的相關圖片合併到一張大圖片裏
而後用css的background-position定位到大圖的具體局部位置
好比這樣:
可是近年來好像用的愈來愈少了
想一想緣由,應該是。。。。維護起來[太麻煩]了
只要稍微改動一張圖片,尤爲是改變了大小的話,整個大圖片都要改
而且還要把css樣式也改個遍
不然就是繼續往大圖片裏拼,無效的老圖保留,致使圖片愈來愈臃腫
再有,若是隻是一些這樣的小圖標的話,用fonticon要方便得多
iconfont就是圖標字體,將圖標輸出爲矢量的字體
使用起來很是方便,對應字體的編碼,就和網頁中的普通文字同樣
<i class="icon iconfont">U</i>
它對比合並的圖片來講
體積會更小,而且能用css控制大小,顏色
而後它仍是矢量的,放大也不失真
雖然iconfont製做,維護成本也不低,引用起來爲兼容瀏覽器得引用多種格式
但好在如今用的人多,網上也有許多免費圖標庫供使用
好比這裏阿里巴巴圖標庫
引用css放在<head>內,引用js放在</body>結束標籤前,如今不少朋友都會這麼作了
css加載是異步的,更早的加載出樣式就能更早呈現出頁面
js放在尾部,防止瀏覽器加載js而阻塞頁面,形成頁面「白屏」現象
若是有條件的話,咱們還能夠啓用額外的服務器,域名來存放資源
這樣能減小主域名的HTTP請求數,讓主服務器更快響應請求
還能減小主域名的cookie請求
緩存
說到緩存,首先想到的確定是服務器後臺的緩存
其實,打開咱們的瀏覽器工具看一下,就會發現,網頁前臺也存在着許多緩存
它無聲無息,悄悄優化着每一次訪問
直接看響應頭,咱們會發現這些字段:
Expires:Thu, 20 Oct 2016 06:43:43 GMT //告訴瀏覽器此日期之前可使用緩存文件
Cache-Control:public, max-age=3600 //表示資源在3600毫秒以內可使用緩存文件,若是和Expires同時存在則覆蓋Expires
Last-Modified:Wed, 13 Jul 2015 08:52:12 GMT//配合Cache-Controls使用,標示資源的最後修改日期
ETag:5384183131862232576//配合Cache-Controls使用,標示資源由服務器生成的惟一標識(某些資源最後修改日期不可靠,或者不但願展現最後修改日期,就可使用ETag)
上面這些都是控制前端緩存的字段,而後再來看看下面的HTTP狀態碼
//200 OK 請求已成功,請求所但願的響應頭或數據體將隨此響應返回。
//304 Not Modified 請求資源沒有改變,可使用緩存資源
因此這裏當咱們第一次訪問的時候,獲得響應資源及緩存策略,
以後若是緩存有效,資源就會來自緩存
若是緩存無效了,就會判斷是否有Last-Modified或者ETag,有則發送If-Modified-Since或If-None-Match請求頭
服務器若是判斷資源無修改,就會返回304,有修改就會返回200以及新的緩存策略
固然,這裏只是指用戶的普通操做,如:地址欄回車,頁面連接跳轉,新窗口,前進後退
若是用戶是進行 刷新 操做,則不會讀取緩存資源了,可是若是有Last-Modified或者ETag,依然會發送If-Modified-Since或If-None-Match請求頭
若是用戶是進行 強制刷新(ctrl+f5) 操做,那全部緩存策略都失效,會從新請求
可見,咱們每每只有第一次請求的時候,纔會有較多的資源加載
因此咱們上面作了這麼多優化,延遲加載,資源壓縮,合併等等,
都是爲了用戶第一次訪問的時候儘可能友好。
那麼Cache-Control要如何在服務器設置呢,其實針對靜態資源來講
大部分服務器都會默認就將Cache-Control設置好了的,咱們能夠視狀況修改一些時效參數等等
咱們這裏要注意的是用url去控制緩存的有效性
以下:
雖然它們請求的都是服務器上的同一個js文件,可是瀏覽器不會把它們看成同一個資源
能夠看到v=1.01.js的請求是來源於cache
其餘幾個請求都是新請求
因此,咱們每次發佈均可以修改資源url強制讓用戶頁面上的緩存失效
這樣用戶不須要刷新也能獲得最新的資源
離線存儲在我以前一篇文章裏也提到過,在移動端應用的比較多
它和緩存不一樣,它設置好了以後,連離線也能訪問,不管用戶刷新或者新窗口,連接等等
使用manifest
<html manifest="/mobile.manifest">
在html上添加manifest,其中文件格式內容如:
CACHE MANIFEST ##須要離線的內容 CACHE: Script/jquery.js Script/gameconfig.js Image/home.png Image/logo.png ##老是訪問網絡的內容 NETWORK: * ##訪問A失敗時訪問B FALLBACK
瀏覽器將緩存chache內全部的內容,而且能夠離線訪問,只要文件發生任何改變都將會從新讀取並刷新所有緩存,因此更改註釋是個更新緩存的好方法
這裏要注意的是
1,添加了manifest的當前網頁也會被緩存 因此推薦的方式是頁面緩存,頁面動態內容所有用ajax獲取,因此在移動網站項目設計開始就要注意這個問題
2,頁面中添加iframe 而後子頁面引用manifest想達到緩存資源而不緩存當前頁面內容,是無效的。
本地存儲數據一直是網頁端的弱項,在沒有HTML5的localStorage前,用cookie能夠保存一點數據
但付出的代價很大,cookie能保存的數據不多,而且它會伴隨着每一次請求一塊兒發送
localStorage就好多了,默認5MB的大小,除非用戶手動清除,不然一直不過時,就連IE8瀏覽器都支持
這裏要注意,localStorage和cookie同樣受到跨域的限制
可使用domain控制
document.domain="";
其它的
在js中,咱們實現動畫,就是利用定時器循環改變dom元素的屬性來達到動畫效果
可是許多屬性更改以後會形成瀏覽器重繪,增長性能消耗
固然瀏覽器更新換代也作了許多優化,咱們優化js,css減小重繪,也能改進動畫性能
可是想想,究竟應不該該讓js去實現頁面動畫呢?
css3就是往這方面發展,讓js更純粹的去實現業務邏輯
頁面效果之類的事情就讓css去作吧
而且css3在動畫效率上面也有加強,瀏覽器會單獨處理css3動畫,不佔用js主線程,還能夠硬件加速
未來還有提高的可能,因此快把咱們的js動畫替換爲css3吧!
一樣更迭的還有flash,當初flash是爲了彌補網頁展示的不足而出現的「插件」
而如今網頁標準一次次升級,html5的出現,再加上flash自身也有各類漏洞,性能問題
尤爲是如今flash在移動端的支持不多,都加快了咱們替換flash的步伐
寫到這裏快寫完了,忽然發現好像本身在囉囉嗦嗦了一整頁。。
卻又感受哪裏漏都了一些,好吧,但願你們不要嫌煩,若是都瞭解了,就當溫習吧
若有紕漏,歡迎提醒
哦,還有些想說的
優化必定要選擇適合本身項目,硬件條件的優化方式,千萬不要盲目硬搬
還有要持續不斷的關注新標準,方法,一直保持活力!