天天看點

如何讓你的網頁打開速度降低到 1s 内

還記得圖檔延遲加載方案 那篇博文嗎?當初分析了 

定寬高值

 和 

定寬高比

 這兩種常見的圖檔延遲加載場景,也介紹了他們的應對方案,還做了一點技術選型的工作。

經過一段時間的項目實踐,在先前方案的基礎上又做了很多深入的優化工作。最終将好奇心日報的網頁打開速度将降低到了1s内,Web端和Mobile端加載3屏資料消耗的流量也大幅降低。

如何讓你的網頁打開速度降低到 1s 内

模拟WIFI條件下的網頁加載

該篇文章結合具體的項目實踐,将圍繞如何更快的通路網頁展開,細化到具體的技術方案,以及實踐中可能遇到的坑,希望對大家有一定的啟發和幫助。

為什麼要優化網頁加載速度?

好奇心日報無論是設計還是内容都追求高品質,于是豐富的圖文混合成了标配:首頁的banner圖,文章詳情頁的配圖,研究所有趣的gif圖等等。

特别嚴重的時候,一篇文章有十多個gif圖,加載花費的時間10-20秒之長,加載消耗的流量幾十M之多,嚴重影響了使用者體驗!尤其是Mobile端,一寸流量一寸金;3-5s打不開頁面,使用者都會直接逃離。是以網頁加載速度優化勢在必行!

我們都知道一個網頁的加載流程大緻如下:

1、解析HTML結構。

2、加載外部腳本和樣式表檔案。

3、解析并執行腳本代碼。// 部分腳本會阻塞頁面的加載

4、DOM樹建構完成。//DOMContentLoaded 事件

5、加載圖檔等外部檔案。

6、頁面加載完畢。//load 事件

一句話就是:請求HTML,然後順帶将HTML依賴的JS/CSS/iconfont等其他資源一并請求過來。

那麼優化網頁的加載速度,最本質的方式就是:減少請求數量 與 減小請求大小。

減少請求數量

1、将小圖示合并成sprite圖或者iconfont字型檔案

2、用base64減少不必要的網絡請求

3、圖檔延遲加載

4、JS/CSS按需打包

5、延遲加載ga統計

6、等等...

減小請求大小

1、JS/CSS/HTML壓縮

2、gzip壓縮

3、JS/CSS按需加載

4、圖檔壓縮,jpg優化

5、webp優化 & srcset優化

JS/CSS按需打包

JS/CSS按需加載

 是兩個不同的概念:

JS/CSS按需打包

 是預編譯發生的事情,保證隻打包目前頁面相關的邏輯。

JS/CSS按需加載

 是運作時發生的事情,保證隻加載目前頁面第一時間使用到的邏輯。

接下來我們将結合兩個本質的優化方式介紹具體的實踐方法。

如何減少請求數量?

1、合并圖示,減少網絡請求

合并圖示是減少網絡請求的常見的優化手段,網頁中的小圖示特征是體積小、數量多,而浏覽器同時發起的并行請求數量又是有限制的,是以這些小圖示會嚴重的影響網頁的加載速度,阻礙關鍵内容的請求和呈現

sprite圖

合并sprite圖是慢工細活兒,并沒有特别大的技術含量,但卻是每個前端開發都必須掌握的技術。

剛入門的前端直接手動切圖拼圖即可。

經驗豐富的前端可以嘗試利用建構工具實作自動化,推薦使用。 gulp.spritesmith插件 。

// 建構視圖檔案gulp.task('sprites', function() {    var spriteData = gulp.src(config.src)
        .pipe(plumber(handleErrors))
        .pipe(newer(config.imgDest))
        .pipe(logger({ showChange: true }))
        .pipe(spritesmith({
            cssName: 'sprites.css',
            imgName: 'sprites.png',
            cssTemplate: path.resolve('./gulp/lib/template.css.handlebars')
        }));    var imgStream = spriteData.img
        .pipe(buffer())
        .pipe(gulp.dest(config.imgDest));    var cssStream = spriteData.css
        .pipe(gulp.dest(config.cssDest));    return merge([imgStream, cssStream]);
});      

sprite圖不适合無線端的響應式場景,是以越來越作為一個備用方案。

iconfont字型檔案

iconfont字型檔案是用字型編碼的形式來實作圖示效果,既然是文字,那就可以随意設定顔色設定大小,相對來說比sprite方案更好。但是它隻适用于純×××标。推薦使用阿裡巴巴矢量圖示庫

如何讓你的網頁打開速度降低到 1s 内

base64碼相容性

上文提到的sprite圖和iconfont字型檔案,對于有些場景并不适合,比如:

1、小背景圖,無法放到精靈圖中,通常循環平鋪小塊來設定大背景。

2、小gif圖,無法放到精靈圖中,發請求又太浪費。

如何讓你的網頁打開速度降低到 1s 内

base64使用場景

注意:cssnano壓縮css的時候,對于部分規則的base64 uri不能識别,會出現誤傷,如下圖,cssnano壓縮的時候會将 

//

 壓縮為 

/

 :

如何讓你的網頁打開速度降低到 1s 内

cssnano壓縮base64

原因是:cssnano會跳過 

data:p_w_picpath

 / 

data:application

 後面的字元串,但是不會跳過 

data:img

 ,是以如果你使用的工具生成的是 

data:img

 ,建議換工具或者直接将其修改為 

data:p_w_picpath

 。

圖檔是網頁中流量占比最多的部分,也是需要重點優化的部分。

圖檔延遲加載的原理就是先不設定img的src屬性,等合适的時機(比如滾動、滑動、出現在視窗内等)再把圖檔真實url放到img的src屬性上。更多内容請移步上一篇博文:圖檔延遲加載方案

固定寬高值的圖檔

固定寬高值的圖檔延遲加載比較簡單,因為寬高值都可以設定在css中,隻需考慮src的替換問題,推薦使用 lazysizes 。

// 引入js檔案<script src="lazysizes.min.js" async=""></script>// 非響應式 例子<img src="" data-src="p_w_picpath.jpg" class="lazyload" />// 響應式 例子,自動計算合适的圖檔<img    data-sizes="auto"
    data-src="p_w_picpath2.jpg"
    data-srcset="p_w_picpath1.jpg 300w,
    p_w_picpath2.jpg 600w,
    p_w_picpath3.jpg 900w" class="lazyload" />// iframe 例子<iframe frameborder="0"
    class="lazyload"
    allowfullscreen=""
    data-src="//www.youtube.com/embed/ZfV-aYdU4uE"></iframe>      

注意:浏覽器解析img标簽的時候,如果src屬性為空,浏覽器會認為這個圖檔是壞掉的圖,會顯示出圖檔的邊框,影響市容。

如何讓你的網頁打開速度降低到 1s 内

第一塊是初始狀态,第四塊是成功狀态,第二塊第三塊是影響市容的狀态

lazysizes延遲加載過程中會改變圖檔的class:預設lazyload,加載中lazyloading,加載結束:lazyloaded。結合這個特性我們有兩種解決上述問題辦法:

1、設定opacity:0,然後在顯示的時候設定opacity:1。

// 漸現 lazyload.lazyload,
.lazyloading{
    opacity: 0;
}
.lazyloaded{
    opacity: 1;
    transition: opacity 500ms; //加上transition就可以實作漸現的效果}      

2、用一張預設的圖占位,比如1x1的透明圖或者灰圖。

<img class="lazyload" 
    src="data:p_w_picpath/gif;base64,R0lGODlhAQABAAA
       AACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 
    data-src="真實url" 
    alt="<%= article.title %>">      

此外,為了讓效果更佳,尤其是文章詳情頁中的大圖,我們可以加上loading效果。

.article-detail-bd {
    .lazyload {
        opacity: 0;
    }
    .lazyloading {
        opacity: 1;
        background: #f7f7f7 url(/p_w_picpaths/loading.gif) no-repeat center;
    }
}      

固定寬高比的圖檔

固定寬高比的圖檔延遲加載相對來說複雜很多,比如文章詳情頁的圖檔,由于裝置的寬度值不确定,是以高度值也不确定,這時候工作的重心反倒放到了如何确定圖檔的高度上。

為什麼要确定圖檔的高度呢?因為單個圖檔的加載是從上往下,是以會導緻頁面抖動,不僅使用者體驗很差,而且對于性能消耗很大,因為每次抖動都會觸發reflow(重繪)事件,之前的博文 網站性能優化 之 渲染性能 也分析過重繪對于性能的消耗問題。

固定寬高比的圖檔抖動問題,有下列兩種主流的方式可以解決:

1、第一種方案使用padding-top或者padding-bottom來實作固定寬高比。優點是純CSS方案,缺點是HTML備援,并且對輸出到第三方不友好。

<div style="padding-top:75%">
    <img data-src="" alt="" class="lazyload"><div>      

2、第二種方案在頁面初始化階段利用ratio設定實際寬高值,優點是html幹淨,對輸出到第三方友好,缺點是依賴js,理論上會至少抖動一次。

<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中,就為了一個目的,第一時間計算圖檔的高度值,降低使用者感覺到頁面抖動的可能性,保證最佳效果。

// 原生代碼<img alt="" 
    data-ratio="0.562500" 
    data-format="jpeg" 
    class="lazyload" 
    data-src="http://img.qdaily.com/uploads/20160807124000WFJNyGam85slTC4H.jpg" 
    src="">// 解析之後的代碼<img alt="" 
    data-ratio="0.562500" 
    data-format="jpeg" 
    class="lazyloaded" 
    data-src="http://img.qdaily.com/uploads/20160807124000WFJNyGam85slTC4H.jpg" 
    src="http://img.qdaily.com/uploads/20160807124000WFJNyGam85slTC4H.jpg" 
    style="height: 323.438px;">      

我們不僅儲存了寬高比,還儲存了圖檔格式,是為了後期可以對gif做進一步的優化。

注意事項

1、避免圖檔過早加載,把臨界值調低一點。在實際項目中,并不需要過早就把圖檔請求過來,尤其是Mobile項目,過早請求不僅浪費流量,也會因為請求太多,導緻頁面加載速度變慢。

2、為了最好的防抖效果,設定圖檔高度的JS代碼内嵌到HTML中以便第一時間執行。

3、根據圖檔寬度設定高度時,使用clientWidth而不是width。這是因為Safari中,第一時間執行的JS代碼擷取圖檔的width失敗,是以使用clientWidth解決這個問題。

按需打包是webpack獨特的優勢,如果有需要通過此種方式來管理子產品之間的依賴關系,強烈推薦引入!webpack門檻較高,可以看看我之前的部落格:

webpack 入門

webpack 子產品化機制

好奇心日報是典型的多頁應用,為了緩存通用代碼,我們使用webpack按需打包的同時,還利用webpack的 

CommonsChunkPlugin 插件

 抽離出公用的JS/CSS代碼,便于緩存,在請求數量和公用代碼的緩存之間做了一個很好的平衡。

async & defer屬性

html5中給script标簽引入了async和defer屬性。

帶有async屬性的script标簽,會在浏覽器解析時立即下載下傳腳本同時不阻塞後續的document渲染和script加載等事件,進而實作腳本的異步加載。

帶有defer屬性的script标簽,和async擁有類似的功能。并且他們有可以附帶一個onload事件 

<script src="" defer onload="init()">

async和defer的差別在于:async屬性會在腳本下載下傳完成後無序立即執行,defer屬性會在腳本下載下傳完成後按照document結構順序執行。

由于defer和async的相容性問題,我們通常使用 

動态建立script标簽

 的方式來實作異步加載腳本,即 

document.write('<script src="" async></script>');

,該方式也可以避免阻塞。

ga統計代碼

ga統計代碼采用就是 

動态建立script标簽

 方案。

該方法不阻塞頁面渲染,不阻塞後續請求,但會阻塞window.onload事件,頁面的表現方式是進度條一直加載或loading菊花一直轉。

是以我們延遲執行ga初始化代碼,将其放到window.onload函數中去執行,可以防止ga腳本阻塞window.onload事件。進而讓使用者感受到更快的加載速度。

如何讓你的網頁打開速度降低到 1s 内

将ga加載綁定到onload事件上

如何減小請求大小?

這也是正常手段,就不介紹太多,主要的方式有:

1、通過建構工具實作,比如webpack/gulp/fis/grunt等。

2、背景預編譯。

3、利用第三方online平台,手動上傳壓縮。

無論是第二種還是第三種方式,都有其局限性,第一種方法是目前的主流方式,憑借良好的插件生态,可以實作豐富的建構任務。

在好奇心日報的項目中,我們使用webpack & gulp作為建構系統的基礎。

簡單介紹一下JS/CSS/HTML壓縮方式和一些注意事項

JS壓縮

JS壓縮

 :使用webpack的 

UglifyJsPlugin

 插件,同時做一些代碼檢測。

new webpack.optimize.UglifyJsPlugin({    mangle: {
        except: ['$super', '$', 'exports', 'require']
    }})      

CSS壓縮

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
    ];      

HTML壓縮

HTML壓縮

 :使用htmlmin壓縮HTML,同時對不規範的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));
});      

某個第三方平台要求 

<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0, user-scalable=no">

 必須寫成小數點格式,而htmlmin預設會将小數格式化為整數,是以額外添加了排除項: 

/<meta[\s\S]*?name="viewport"[\s\S]*?>/

 。到現在都沒懂這個第三方平台咋想的!

條件編譯

由于好奇心日報項目較多,我們費了很大的心思抽離出前端項目,實作了前後分離。但有些場景下,我們為了将相關代碼維護在一個檔案中,同時又針對不同項目執行不同的邏輯,這時候,強烈推薦使用 gulp-preprocess插件 來實作條件編譯。

如何讓你的網頁打開速度降低到 1s 内

gzip壓縮也是比較正常的優化手段。前端并不需要做什麼實際的工作,背景配置下伺服器就行,效果非常明顯。如果你發現你的網站還沒有配置gzip,那麼趕緊行動起來吧。

gzip壓縮原理

如果浏覽器支援gzip壓縮,在發送請求的時候,請求頭中會帶有 

Accept-Encoding:gzip

 。然後伺服器會将 

原始的response

 進行gzip壓縮,并将 

gzip壓縮後的response

 傳輸到浏覽器,緊接着浏覽器進行gzip解壓縮,并最終回報到網頁上。

如何讓你的網頁打開速度降低到 1s 内

支援gzip壓縮的請求頭

gzip壓縮效果

那麼gzip壓縮的效果有多明顯呢?保守估計,在已經完成JS/CSS/HTML壓縮的基礎上,還能降低60-80%左右的大小。

如何讓你的網頁打開速度降低到 1s 内

但需要注意,gzip壓縮會消耗伺服器的性能,不能過度壓縮。

是以推薦隻對JS/CSS/HTML等資源做gzip壓縮。圖檔的話,托管到第三方的圖檔建議開啟gzip壓縮,托管到自己應用伺服器的圖檔不建議開啟gzip壓縮。

和前面提到的按需打包不同。

JS/CSS按需打包

JS/CSS按需加載

那麼怎麼實作按需加載呢?好奇心日報使用webpack提供的 

require

 及 

require.ensure

 方法來實作按需加載,值得一提的是,除了指定的按需加載檔案清單,webpack還會自動解析回調函數的依賴及指定清單的深層次依賴,并最終打包成一個檔案。

如何讓你的網頁打開速度降低到 1s 内

webpack按需加載

上訴代碼的實作效果是:隻有當點選登入按鈕的時候,才會去加載登入相關的JS/CSS資源。資源在加載成功後自動執行。

托管到應用伺服器的圖檔壓縮

可以手動處理,也可以通過gulp子任務來處理。

手動處理的話,推薦一個網站 tinypng ,雖然是有損壓縮,但壓縮效果極好。

gulp子任務處理的話,推薦使用 gulp-p_w_picpathmin插件 ,自動化處理,效果也還不錯。

// 圖檔壓縮gulp.task('p_w_picpaths', function() {    return gulp.src(config.src)
        .pipe(plumber(handleErrors))
        .pipe(newer(config.dest))
        .pipe(logger({ showChange: true }))
        .pipe(p_w_picpathmin()) // 壓縮
        .pipe(gulp.dest(config.dest));
});      

托管到第三方平台的圖檔壓縮

比如七牛雲平台,他們會有一套專門的方案來對圖檔壓縮,格式轉換,裁剪等。隻需要在url後面加上對應的參數即可,雖然偶爾會有一些小bug,但整體來說,托管方案比用自家應用伺服器方案更優。

如何讓你的網頁打開速度降低到 1s 内

改變參數,實作不同程度的壓縮

jpg優化

除了對圖檔進行壓縮之外,對透明圖床沒有要求的場景,強烈建議将png轉換為jpg,效果很明顯!

如下圖,将png格式化為jpg格式,圖檔相差差不多8倍!

如何讓你的網頁打開速度降低到 1s 内

png轉jpg,體積相差八倍

再次強調,可以轉換成jpg的圖檔,強烈建議轉換成jpg!

webp優化

粗略看一眼,卧槽,相容性這麼差,也就安卓浏覽器及chrome浏覽器對它的支援還算給力。

如何讓你的網頁打開速度降低到 1s 内

webp相容性

另一方面,webp優化能在jpg的基礎上再降低近50%的大小。其優化效果明顯。此外,如果浏覽器支援webpanimation,還能對gif做壓縮!

如何讓你的網頁打開速度降低到 1s 内

普通圖檔webp優化

如何讓你的網頁打開速度降低到 1s 内

gif圖檔優化

相容性差,但效果好!最終好奇心決定嘗試一下。

1、判斷浏覽器對webp及webpanimation的相容性。

2、如果浏覽器支援webp及webpanimation,将其替換成webp格式的圖檔。

鑒于浏覽器對webp的支援比較局限,我們采用漸進更新的方式來優化:對于不支援webp的浏覽器,不做處理;對于支援webp的浏覽器,将圖檔src替換成webp格式。

那麼如何判斷webp相容性呢?

// 檢測浏覽器是否支援webp// 之是以沒寫成回調,是因為即使isSupportWebp=false也無大礙,但卻可以讓代碼更容易維護(function() {    function webpTest(src, name) {
        var img = new Image(),
            isSupport = false,
            className, cls;

        img.onload = function() {
            isSupport = !!(img.height > 0 && img.width > 0);

            cls = isSupport ? (' ' + name) : (' no-' + name);
            className = document.querySelector('html').className
            className += cls;

            document.querySelector('html').className = className.trim();
        };
        img.onerror = function() {
            cls = (' no-' + name);
            className = document.querySelector('html').className
            className += cls;

            document.querySelector('html').className = className.trim();
        };

        img.src = src;
    }    var webpSrc = 'data:p_w_picpath/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoB\
                AAEAAwA0JaQAA3AA/vuUAAA=',
        webpanimationSrc = 'data:p_w_picpath/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAA\
                            SAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAA\
                            AAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA';

    webpTest(webpSrc, 'webp');
    webpTest(webpanimationSrc, 'webpanimation');
})();      

借鑒modernizr,實作了檢測webp/webpanimation相容性的函數,從代碼中可以看出,檢測原理就是模拟下載下傳對應格式的圖檔,在異步函數中可以得到相容性結果。

接下來就是替換url為webp格式

// 擷取webp格式的srcfunction _getWebpSrc(src) {
    var dpr = Math.round(window.devicePixelRatio || 1),
        ratio = [1, 1, 1.5, 2, 2, 2],
        elHtml = document.querySelector('html'),
        isSupportWebp = (/(^|\s)webp(\s|$)/i).test(elHtml.className),
        isSupportWebpAnimation = (/(^|\s)webpanimation(\s|$)/i).test(elHtml.className),
        deviceWidth = elHtml.clientWidth,
        isQiniuSrc = /img\.qdaily\.com\//.test(src),
        format = _getFormat(src),
        isGifWebp, isNotGifWebp, regDetailImg;    if (!src || !isQiniuSrc || !format || format == 'webp') {        return src;
    }

    isNotGifWebp = (format != 'gif' && isSupportWebp);
    isGifWebp = (format == 'gif' && isSupportWebpAnimation);    // 根據螢幕分辨率計算大小
    src = src.replace(/\/(thumbnail|crop)\/.*?(\d+)x(\d+)[^\/]*\//ig, function(match, p0, p1, p2) {        if(dpr > 1){
            p1 = Math.round(p1 * ratio[dpr]);
            p2 = Math.round(p2 * ratio[dpr]);

            match = match.replace(/\d+x\d+/, p1 + 'x' + p2)
        }        return match;
    });    if(isNotGifWebp || isGifWebp) {       // 替換webp格式,首頁/清單頁
        src = src.replace(/\/format\/([^\/]*)/ig, function(match, p1) {            return '/format/webp';
        });
    }
}      

1、window的螢幕像素密度不一定是整數,mac浏覽器縮放之後,螢幕像素密度也不是整數。是以擷取dpr一定要取整: 

dpr = Math.round(window.devicePixelRatio || 1);

2、 

ratio = [1, 1, 1.5, 2, 2, 2]

 表示:1倍屏使用1倍圖,2倍屏使用1.5倍圖,3倍屏以上都用2倍圖。這兒的規則可以按實際情況來設定。

3、webp優化更适合托管到第三方的圖檔,簡單修改參數就可以擷取不同的圖檔。

如何讓你的網頁打開速度降低到 1s 内

devicePixelRatio相容性

srcset相容性

如何讓你的網頁打開速度降低到 1s 内

如上所述,在對webp優化的時候,我們順道模拟實作了srcset:根據螢幕像素密度來設定最适合的圖檔寬高。

lazysizes原本提供了srcset選項,也可以借用lazysizes的方案來實作srcset,有興趣的可以去看看源碼。

又到總結的時候了?

本部落格圍繞好奇心日報的具體實踐,在優化頁面加載速度方面的做了一系列思考。整體來說,涉及的知識面比較廣:包括webpack & gulp的建構系統、圖檔的webp優化、伺服器的gzip配置、浏覽器的加載順序、圖檔延遲加載方案等等。