咱們經過一個示例來講明什麼是懶加載。html
// a,js import './common' console.log('A') export default 'A' // b.js import './common' console.log('B') export default 'B' // common.js console.log('公共模塊') export default 'common' // 異步代碼 import(/* webpackChunkName: 'a'*/ './a').then(function(a) { console.log(a) }) import(/* webpackChunkName: 'b'*/ './b').then(function(b) { console.log(b) }) document.addEventListener('click', () => { // 異步加載lodash模塊 import('lodash').then(({default: _}) => { console.log(_.join(['3', '4'])) }) })
目錄結構:
配置webpack.config.js
:前端
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin module.exports = { entry: { main: './lazyloading/index.js' }, output: { path: path.resolve(__dirname, 'build'), // 打包文件的輸出目錄 filename: '[name].bundle.js', // 代碼打包後的文件名 publicPath: __dirname + '/build/', // 引用的路徑或者 CDN 地址 chunkFilename: '[name].js' // 代碼拆分後的文件名 }, // 拆分代碼配置項 optimization: { splitChunks: { chunks: 'all', minSize: 30000, maxSize: 0, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: { lodash: { name: 'lodash', test: /[\\/]node_modules[\\/]/, priority: 10 }, common: { name: 'common', minSize: 0, //表示在壓縮前的最小模塊大小,默認值是 30kb,若是沒設置爲0,common模塊就不會抽離爲公共模塊,由於原始大小小於30kb minChunks: 2, // 最小公用次數 priority: 5, // 優先級 reuseExistingChunk: true // 公共模塊必開啓 }, vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } }, plugins: [ new CleanWebpackPlugin(), // 會刪除上次構建的文件,而後從新構建 new BundleAnalyzerPlugin() ] }
咱們打包執行index.html
,當點擊頁面的時候,異步加載lodash
並輸出內容,演示以下:
node
第一次進入頁面時並無加載lodash
模塊,當我點擊頁面時,瀏覽器再去加載lodash
,並執行輸出,這就是所謂的懶加載。webpack
其實懶加載就是經過import
去異步加載一個模塊,至於何時去加載,這個要根據業務邏輯來寫,好比彈窗組件、模態框組件等等,都是點擊按鈕以後纔出現。web
懶加載可以加快頁面的加載速度,若是你把詳情頁、彈窗等頁面所有打包放在一個js
中,當用戶只是訪問首頁,只須要首頁的代碼,不須要其餘頁面的代碼,加入多餘的代碼只會使得加載時間變長。chrome
import
後面返回的是一個 then
,說明這是一個 promise
類型,一些低端的瀏覽器不支持 promise
,好比 IE
,若是要使用這種異步的代碼,就要使用 babel
以及 babel-polyfill
來作轉換,由於我使用的是高版本的 chrome
瀏覽器,對 ES6
語法是支持的,因此我並無安裝 babel
也能使用。promise
如今咱們再列舉一個示例證明懶加載在性能方面的優化瀏覽器
更改index.js
:緩存
// 異步代碼 import(/* webpackChunkName: 'a'*/ './a').then(function(a) { console.log(a) }) import(/* webpackChunkName: 'b'*/ './b').then(function(b) { console.log(b) }) document.addEventListener('click', () => { var element = document.createElement('div') element.innerHTML = "hello world" document.body.appendChild(element) })
從新打包,並打開 index.html
,打開瀏覽器控制檯,按 ctrl + shift + p
,輸入 coverage
就能看到當前頁面加載的 js
代碼未使用率,紅色區域表示未被使用的代碼段
這裏一開始紅色區域的代碼未被使用,當我點擊了頁面後,變成綠色,頁面出現了 Hello World
,說明代碼被使用了性能優化
頁面剛加載的時候,異步的代碼根本就不會執行,可是咱們卻把它下載下來,實際上就會浪費頁面執行性能,webpack
就但願像這樣交互的功能,應該把它放到一個異步加載的模塊去寫
新建一個 click.js
文件
function handleClick() { var element = document.createElement('div') element.innerHTML = 'hello world' document.body.appendChild(element) } export default handleClick
而且將 index.js
文件改成異步的加載模塊:
document.addEventListener('click', () => { import('./click.js').then(({default: fn}) => { fn() }) })
從新打包,使用 coverage
分析
當加載頁面的時候,沒有加載業務邏輯,當點擊網頁的時候,纔會加載 0.js
模塊,也就是咱們在 index.js
中異步引入的 click.js
當click.js
文件越大時,懶加載對性能的提高越加明顯
因此想寫出高性能的代碼,不只僅考慮緩存,更要考慮到代碼的使用率
因此 webpack
在打包過程當中,是但願咱們多寫這種異步的代碼,才能提高網站的性能,這也是爲何 webpack
的 splitChunks
中的 chunks
默認是 async
異步能提升你網頁打開的性能,而同步代碼是增長一個緩存,對性能的提高是很是有限的,由於緩存通常是第二次打開網頁或者刷新頁面的時候,緩存頗有用,可是網頁的性能通常是用戶第一次打開網頁,看首屏的時候。
固然,這也會出現另外一個問題,就是當用戶點擊的時候,纔去加載業務模塊,若是業務模塊比較大的時候,用戶點擊後並無立馬看到效果,而是要等待幾秒,這樣體驗上也很差,怎麼去解決這種問題
一:若是訪問首頁的時候,不須要加載詳情頁的邏輯,等用戶首頁加載完了之後,頁面展現出來了,頁面的帶寬被釋放出來了,網絡空閒了,再「偷偷」的去加載詳情頁的內容,而不是等用戶去點擊的時候再去加載
這個解決方案就是依賴 webpack
的 Prefetching/Preloading 特性
修改index.js
:
document.addEventListener('click', () => { import(/* webpackPrefetch: true */ './click.js').then(({default: fn}) => { fn() }) })
webpackPrefetch: true
會等你主要的 JS
都加載完了以後,網絡帶寬空閒的時候,它就會預先幫你加載好
從新打包後刷新頁面,注意看 Network
能夠看到尚未點擊頁面時,當主要的js
都加載完後,0.js
(也就是click.js
)在網絡空閒時就加載了。點擊頁面時,第二次加載就利用緩存中的0.js
,發現加載時間由29ms
縮減到4ms
,可想而知預加載對頁面性能提高的重要性。
這裏咱們使用的是 webpackPrefetch
,還有一種是 webpackPreload
區別:與 prefetch 相比,Preload 指令有不少不一樣之處:
Prefetch會等待覈心代碼加載完以後,有空閒以後再去加載。Preload 會和核心的代碼並行加載,仍是不推薦
總結:
針對優化,不只僅是侷限於緩存,緩存能帶來的代碼性能提高是很是有限的,而是如何讓代碼的使用率最高,有一些交互後才用的代碼,能夠寫到異步組件裏面去,經過懶加載的形式,去把代碼邏輯加載進來,這樣會使得頁面訪問速度變的更快,若是你以爲懶加載會影響用戶體驗,可使用 Prefetch 這種方式來預加載,不過在某些遊覽器不兼容,會有兼容性的問題,重點不是在 Prefetch 怎麼去用,而是在作前端代碼性能優化的時候,緩存不是最重要的點,最重要的是代碼使用的覆蓋率上(coverage)