先看一下網頁的加載流程:javascript
1.解析html結構
2.加載外部腳本和樣式表文件
3.解析並執行腳本(腳本會阻塞頁面的加載)
4.DOM樹構建完成 (DOMContentLoaded)
5.加載圖片等外部文件
6.頁面加載完畢 (load事件)css
THE WAY: 減小請求數量、減少請求大小html
減小請求數量
1.將小圖合併成雪碧圖(sprite)或者iconfont字體文件
2.使用base64減小請求(把圖片轉換成base64)
3.圖片延遲加載
4.JS/CSS按需打包
......前端
減少請求大小
1.JS/CSS/HTML 壓縮
2.gzip壓縮
3.圖片壓縮、JPG優化
4.webp優化
5.JS/CSS按需加載 (require)
......java
NEXT講一下具體的實現webpack
減小請求數量-->
1.sprite圖
可使用構建工具(gulp.spritesmith插件)自動化生成。
2.base64
即把小圖,不必發請求的轉成base64格式
3.圖片延遲加載
圖片延遲加載的原理就是先不設置img的src屬性,等合適的時機(好比滾動、滑動、出如今視窗內等)再把圖片真實url放到img的src屬性上。
(1) 固定寬高的圖片
可使用lazysizes: git
// 引入js文件 <script src="lazysizes.min.js" async=""></script> // 非響應式 例子 <img src="" data-src="image.jpg" class="lazyload" /> // 響應式 例子,自動計算合適的圖片 <img data-sizes="auto" data-src="image2.jpg" data-srcset="image1.jpg 300w, image2.jpg 600w, image3.jpg 900w" class="lazyload" /> // iframe 例子 <iframe frameborder="0" class="lazyload" allowfullscreen="" data-src="//www.youtube.com/embed/ZfV-aYdU4uE"> </iframe>
(2) 固定寬高比的圖片
不一樣設備的寬度不一樣致使高度也相應的不一樣,因此單個圖片從上往下加載完都會有抖動,每次抖動都會形成reflow(重繪),嚴重影響性能
對此有兩種解決方案:github
1⃣️第一種方案使用padding-top或者padding-bottom來實現固定寬高比。優勢是純CSS方案,缺點是HTML冗餘,而且對輸出到第三方不友好。web
<div style="padding-top:75%"> <img data-src="" alt="" class="lazyload"> <div>
2⃣️第二種方案在頁面初始化階段利用ratio設置實際寬高值,優勢是html乾淨,對輸出到第三方友好,缺點是依賴js,理論上會至少抖動一次。gulp
<img data-src="" alt="" class="lazyload" data-ratio="0.75">
那麼,這個padding-top: 75%;和data-ratio="0.75"的數據從哪兒來呢?在你上傳圖片的時候,須要後臺給你返回原始寬高值,計算獲得寬高比,而後保存到data-ratio上。
好奇心日報採用的第二種方案,主要在於第一種方案對第三方輸出不友好:須要對img設置額外的樣式,但第三方平臺一般不容許引入外部樣式。
肯定第二種方案以後,咱們定義了一個設置圖片高度的函數:
// 重置圖片高度,僅限文章詳情頁 function resetImgHeight(els, placeholder) { var ratio = 0, i, len, width; for (i = 0, len = els.length; i < len; i++) { els[i].src = placeholder; width = els[i].clientWidth; //必定要使用clientWidth if (els[i].attributes['data-ratio']) { ratio = els[i].attributes['data-ratio'].value || 0; ratio = parseFloat(ratio); } if (ratio) { els[i].style.height = (width * ratio) + 'px'; } } }
咱們將以上代碼的定義和調用都直接放到了HTML中,就爲了一個目的,第一時間計算圖片的高度值,下降用戶感知到頁面抖動的可能性,保證最佳效果。
注意事項
1⃣️、避免圖片過早加載,把臨界值調低一點。在實際項目中,並不須要過早就把圖片請求過來,尤爲是Mobile項目,過早請求不只浪費流量,也會由於請求太多,致使頁面加載速度變慢。
2⃣️、爲了最好的防抖效果,設置圖片高度的JS代碼內嵌到HTML中以便第一時間執行。
3⃣、根據圖片寬度設置高度時,使用clientWidth而不是width。這是由於Safari中,第一時間執行的JS代碼獲取圖片的width失敗,因此使用clientWidth解決這個問題。
4.JS/CSS按需打包
推薦前端構建工具webpack
http://webpack.github.io/docs/
好奇心日報是典型的多頁應用,爲了緩存通用代碼,咱們使用webpack按需打包的同時,還利用webpack的CommonsChunkPlugin 插件抽離出公用的JS/CSS代碼,便於緩存,在請求數量和公用代碼的緩存之間作了一個很好的平衡。
減少請求大小-->
1.JS/CSS/HTML壓縮
這也是常規手段,就不介紹太多,主要的方式有:
(1) 經過構建工具實現,好比webpack/gulp/fis/grunt等。
(2) 後臺預編譯。
(3) 利用第三方online平臺,手動上傳壓縮。
不管是第二種仍是第三種方式,都有其侷限性,第一種方法是目前的主流方式,憑藉良好的插件生態,能夠實現豐富的構建任務。
在好奇心日報的項目中,使用webpack & gulp做爲構建系統的基礎。
1⃣️: JS壓縮:使用webpack的UglifyJsPlugin插件,同時作一些代碼檢測。
new webpack.optimize.UglifyJsPlugin({ mangle: { except: ['$super', '$', 'exports', 'require'] } })
2⃣️: CSS壓縮:使用cssnano壓縮,同時使用postcss作一些自動化操做,好比自動加前綴、屬性fallback支持、語法檢測等。
var postcss = [ cssnano({ autoprefixer: false, reduceIdents: false, zindex: false, discardUnused: false, mergeIdents: false }), autoprefixer({ browers: ['last 2 versions', 'ie >= 9', '> 5% in CN'] }), will_change, color_rgba_fallback, opacity, pseudoelements, sorting ];
3⃣️: HTML壓縮:使用htmlmin壓縮HTML。
// 構建視圖文件-build版本 gulp.task('build:views', ['clean:views'], function() { return streamqueue({ objectMode: true }, gulp.src(config.commonSrc, { base: 'src' }), gulp.src(config.layoutsSrc, { base: 'src' }), gulp.src(config.pagesSrc, { base: 'src/pages' }), gulp.src(config.componentsSrc, { base: 'src' }) ) .pipe(plumber(handleErrors)) .pipe(logger({ showChange: true })) .pipe(preprocess({ context: { PROJECT: project } })) .pipe(gulpif(function(file) { if (file.path.indexOf('.html') != -1) { return true; } else { return false; } }, htmlmin({ removeComments: true, collapseWhitespace: true, minifyJS: true, minifyCSS: true, ignoreCustomFragments: [/<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/, /<meta[\s\S]*?name="viewport"[\s\S]*?>/] }))) .pipe(gulp.dest(config.dest)); });
2.gzip壓縮
gzip壓縮也是比較常規的優化手段。前端並不須要作什麼實際的工做,後臺配置下服務器就行,效果很是明顯。若是你發現你的網站尚未配置gzip,那麼趕忙行動起來吧。
若是瀏覽器支持gzip壓縮,在發送請求的時候,請求頭(request Headers)中會帶有Accept-Encoding:gzip。而後服務器會將原始的response進行gzip壓縮,並將gzip壓縮後的response傳輸到瀏覽器,緊接着瀏覽器進行gzip解壓縮,並最終反饋到網頁上。
但須要注意,gzip壓縮會消耗服務器的性能,不能過分壓縮。
因此推薦只對JS/CSS/HTML等資源作gzip壓縮。圖片的話,託管到第三方的圖片建議開啓gzip壓縮,託管到本身應用服務器的圖片不建議開啓gzip壓縮。
3.JS/CSS按需加載
webpack的require
4.圖片壓縮和JPG優化
https://tinypng.com/ (近乎於無損壓縮)
參考:http://www.jianshu.com/p/d857c3ff78d6