更快速將你的頁面展現給用戶[前端優化篇]

如今許多公司每每注重後端優化,而忽略了前端優化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是很合適的
好處顯而易見,無需從新請求整頁,小巧快速,網頁展現也友好一些

善用ajax對前端性能,體驗都是有改善的

可是也要考慮到對搜索引擎的友好,
若是頁面總體功能改變了,或者頁面改動量大就要進行取捨了。

 

預加載  

延遲加載的目的就是減小沒必要要的請求,在用戶有需求時才請求資源
因此對於用戶來講,實際上是有一點點「等待」的過程的

通常會用loading圖,等待文字來改善這裏的用戶體驗


可是有一些需求是但願儘可能少出現這種「等待」過程的

這裏咱們就能夠預加載資源,以下,咱們先在js中加載圖片

 

var img  = new Image();
img.src="test.png";

  

提早加載好了圖片,用戶進行下一步時,圖片則是從瀏覽器緩存中獲取

多頁數據也能夠相似處理,頁面初始能夠默認加載兩頁數據
翻到第二頁時,就ajax去獲取第三頁內容
翻到第三頁時,就去獲取第四頁內容......
老是提早預加載一頁數據

如此可必定程度上減小一些等待的過程


總的來講延遲加載是儘可能少加載資源,預加載則是判斷可能要的資源,儘可能去提早多加載,
都是爲了優化用戶的體驗,適用於不一樣場景

資源優化

網頁中有些資源能夠經過延遲加載等方式減小沒必要要的請求
而許多的javascript腳本,css樣式等資源倒是網頁中必需要加載的

既然不可避免須要加載,那接着,咱們就能夠去優化這些資源

 

資源壓縮(uglify-js,clean-css)  

首先咱們能夠優化資源文件的大小,資源文件變小了,傳輸速度固然也快了
這裏咱們壓縮分爲以下兩種:

 

  • HTTP壓縮,咱們能夠在web服務器內設置壓縮輸出的內容

 

以下,在IIS7內啓用Gzip壓縮

能夠看到,設置了以後資源的HTTP響應多了Content-Encoding:gzip

 

  • 對javascript代碼,css樣式代碼進行語法壓縮,減小文件大小

咱們寫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批處理腳本不是我寫的,是之前在網上搜來的)

 

自動化構建(gulp)  

固然,用這種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服務器內作了處理,請求多個文件,會自動合併
有條件的同窗也能夠這樣進行合併

圖片合併csssprite  


圖片合併目的也是減小http請求,將頁面中須要的相關圖片合併到一張大圖片裏
而後用css的background-position定位到大圖的具體局部位置

好比這樣:


可是近年來好像用的愈來愈少了
想一想緣由,應該是。。。。維護起來[太麻煩]了
只要稍微改動一張圖片,尤爲是改變了大小的話,整個大圖片都要改
而且還要把css樣式也改個遍
不然就是繼續往大圖片裏拼,無效的老圖保留,致使圖片愈來愈臃腫


再有,若是隻是一些這樣的小圖標的話,用fonticon要方便得多

iconfont  

iconfont就是圖標字體,將圖標輸出爲矢量的字體

使用起來很是方便,對應字體的編碼,就和網頁中的普通文字同樣

<i class="icon iconfont">&#85;</i>

  

它對比合並的圖片來講
體積會更小,而且能用css控制大小,顏色
而後它仍是矢量的,放大也不失真


雖然iconfont製做,維護成本也不低,引用起來爲兼容瀏覽器得引用多種格式
但好在如今用的人多,網上也有許多免費圖標庫供使用

好比這裏阿里巴巴圖標庫

http://iconfont.cn/

 

引用優化  

引用css放在<head>內,引用js放在</body>結束標籤前,如今不少朋友都會這麼作了

css加載是異步的,更早的加載出樣式就能更早呈現出頁面
js放在尾部,防止瀏覽器加載js而阻塞頁面,形成頁面「白屏」現象

單獨域名存放資源  


若是有條件的話,咱們還能夠啓用額外的服務器,域名來存放資源

 

這樣能減小主域名的HTTP請求數,讓主服務器更快響應請求
還能減小主域名的cookie請求

 

緩存

說到緩存,首先想到的確定是服務器後臺的緩存
其實,打開咱們的瀏覽器工具看一下,就會發現,網頁前臺也存在着許多緩存
它無聲無息,悄悄優化着每一次訪問
 

Cache-Control緩存策略  

直接看響應頭,咱們會發現這些字段:

 

 

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想達到緩存資源而不緩存當前頁面內容,是無效的。

 

本地存儲localStorage  


本地存儲數據一直是網頁端的弱項,在沒有HTML5的localStorage前,用cookie能夠保存一點數據
但付出的代價很大,cookie能保存的數據不多,而且它會伴隨着每一次請求一塊兒發送


localStorage就好多了,默認5MB的大小,除非用戶手動清除,不然一直不過時,就連IE8瀏覽器都支持


這裏要注意,localStorage和cookie同樣受到跨域的限制
可使用domain控制

document.domain="";

  

其它的

 

css3替換js動畫  

在js中,咱們實現動畫,就是利用定時器循環改變dom元素的屬性來達到動畫效果
可是許多屬性更改以後會形成瀏覽器重繪,增長性能消耗


固然瀏覽器更新換代也作了許多優化,咱們優化js,css減小重繪,也能改進動畫性能
可是想想,究竟應不該該讓js去實現頁面動畫呢?

css3就是往這方面發展,讓js更純粹的去實現業務邏輯
頁面效果之類的事情就讓css去作吧

而且css3在動畫效率上面也有加強,瀏覽器會單獨處理css3動畫,不佔用js主線程,還能夠硬件加速
未來還有提高的可能,因此快把咱們的js動畫替換爲css3吧!

替換flash  

一樣更迭的還有flash,當初flash是爲了彌補網頁展示的不足而出現的「插件」
而如今網頁標準一次次升級,html5的出現,再加上flash自身也有各類漏洞,性能問題
尤爲是如今flash在移動端的支持不多,都加快了咱們替換flash的步伐

結語  

寫到這裏快寫完了,忽然發現好像本身在囉囉嗦嗦了一整頁。。

卻又感受哪裏漏都了一些,好吧,但願你們不要嫌煩,若是都瞭解了,就當溫習吧

若有紕漏,歡迎提醒

 

哦,還有些想說的

優化必定要選擇適合本身項目,硬件條件的優化方式,千萬不要盲目硬搬
還有要持續不斷的關注新標準,方法,一直保持活力!

相關文章
相關標籤/搜索