聊一聊 webpack 中的 preloading 和 Prefetching

聊一聊 webpack 中的 preloading 和 Prefetching

提到 Preloading 和 Prefetching 就不得不先說一下代碼分割,經過下面的例子咱們來講明爲何須要代碼分割?webpack

// index.js
import _ from 'lodash'; // 假設大小爲 1 MB

業務代碼 // 假設大小爲 1 MB
  • 在首次訪問時, index.js 文件的大小爲 2 MB,須要加載的大小是 2 MB
  • 業務代碼改變用戶再次訪問時,index.js 的大小爲 2 MB,須要加載的大小仍是 2 MB

如今進行代碼分割:web

// src/index.js 

業務代碼 // 假設大小爲 1 MB

// src/lodash.js
import _ from 'lodash';
window._ = _; // 之後在其它文件中使用 _ 就可使用 lodash 庫了。
  • 首次訪問時,index.js 1 MB,lodash.js 1 MB , 須要加載的大小是 2 MB,並且此時能夠進行並行加載,速度通常會比上面的快。瀏覽器

  • 業務代碼改變用戶再次訪問時,index.js 1 MB,因爲 lodash.js 文件並無發生變化,因此無需再次加載,由於瀏覽器的緩存中有,因此這次只需加載 1 MB。緩存

從上面的例子能夠看出,代碼分割提升了性能,可是第一次訪問的時間並無減小多少,webpack 想讓第一次訪問的時候也獲得很大的優化。網絡

咱們先從 webpack 中的 SplitChunkPlugin 的默認配置中找到答案,app

optimazition: {
  splitChunks: {
    chunks: 'async', // 異步代碼纔會進行代碼分割
    ...
  }
}

咱們能夠看到,chunks 的配置是 async ,只有當異步時纔會進行代碼分割。異步

webpack 爲何要這樣默認設置呢?async

仍是從下面的例子來講明:函數

建立一個div元素,並在頁面上顯示出來。性能

// index.js
document.addEventListener('click', () => {
  const div = document.createElement('div');
  div.innerHTML = 'hello webpack';
  document.body.appendChild(div);
});

思考上面的代碼寫的有問題嗎?還有優化的空間嗎?

如今咱們將上面的代碼打包在瀏覽器中運行,在瀏覽器中 按 Ctrl + Shift + P ,而後在彈出的對話框中輸入 coverage ,點擊回車,而後再點擊下面的小黑原點,小黑圓點變成紅圓點以後,刷新頁面,會出現下圖所示的頁面:

coverage example

從紅色的方框中能夠看出當前加載的文件中在當前頁面中的利用率爲 74.6%

仔細分析一下上面的代碼,在回調函數中的下面三行代碼只有在點擊頁面以後纔會有用,所以加載頁面時不必加載它們。

const div = document.createElement('div');
div.innerHTML = 'hello webpack';
document.body.appendChild(div);

如今咱們換一種寫法,將它們異步加載進來,如今新建一個 click 文件:

// click.js
function handleClick() {
  const div = document.createElement('div');
  div.innerHTML = 'hello webpack';
  document.body.appendChild(div);
}

export default handleClick;

而後改寫 index.js 文件:

document.addEventListener('click', () => {
  import('./click.js').then(({default: func}) => {
    func();
  })
});

這時候將異步代碼寫在一個單獨的文件中,只有當點擊頁面時纔會去加載 click.js 這個文件。

如今再看此時的代碼利用率爲 75% 有了一點提高,設想若是異步加載在的代碼比較大的話,提高的會比較多。

改變代碼後coverage

如今咱們就看出來 webopack 爲何要使用 chunks: 'async' 這樣的默認配置了。

webpack 優化的側重點是代碼的使用率而不是緩存,只是使用緩存的方式來優化意義是不大的,經過異步的方式提升代碼的利用率才能比較大程度地提升網站的性能。

這也是爲何老提倡寫異步代碼的緣由。

如今又有一個問題,只有當用戶點擊頁面時纔會加載 click.js這個文件,那麼若是這個文件很大,那加載的時間也會很長呀,用戶體驗也不高呀。

那這個問題應該如何解決呢?

有些小夥伴可能會想,能不能在加載完頁面網絡空閒的時候先把這些文件加載進來呀,真聰明,這就是接下來要講的 Preloading 和 Prefetching。

  • Prefetching

    使用方法也比較簡單,就是在要異步加載的文件前面加上 /* webpackPrefetch: true */ 這個 magic comment 便可。

    document.addEventListener('click', () => {
      import(/* webpackPrefetch: true */ './click.js').then(({default: func}) => {
        func();
      })
    });

    Prefetching

    上圖中的 0.js 是 click.js 打包以後,能夠看出在頁面加載完以後的空閒時間尚未點擊頁面時已經加載了 0.js ,當點擊頁面時,0.js 直接從緩存中讀取,所以耗時很是短。

  • Preloading 和 Prefetching 有什麼區別?

    二者的最大區別在於,Prefetching 是在覈心代碼加載完成以後帶寬空閒的時候再去加載,而 Preloading 是和核心代碼文件一塊兒去加載的。

所以,使用 Prefetching 的方式去加載異步文件更合適一些,不過要注意瀏覽器的兼容性問題。

完, 若有不恰當之處,歡迎指正哦。

相關文章
相關標籤/搜索