博客 / 詳情

返回

webpack,單文件懶加載分析實現

log.js文件

module.exports ="lazy load logger"

index.js文件

let oBtn = document.getElementById('btn')

oBtn.addEventListener('click', function () {
    import( /*webpackChunkName: "log"*/ './log.js').then((log) => {
        console.log(log)
    })
})
console.log('index.js內容')

點擊按鈕時,控制枱顯示lazy load logger
webpack在打包後,比之前的單文件加載多出了幾件事情。懶加載的實現主要通過Promise來實現。
實現懶加載,要調用__webpack_require__.e方法,e方法是一個promise狀態保存。e方法中,jsonP創建srcipt標籤,指定src,通過Promise.all把狀態往後傳,在過程中,動態加載要被導入的內容,這裏會通過window['webpackJsonP]調用push方法.調用webpackJsonpCallback方法,執行成功的resolve方法,__webpack_require__.e後的then方法通過__webpack_require__.t方法加載log中的內容放在value中保存.這裏多出的兩個操作一個是jsonP,一個是__webpack_require__.e

// 定義webpackJsonpCallback,合併模塊定義,改變promise狀態,還有之後的then操作
    function webpackJsonpCallback(data) {
        // 獲取要被動態加載的模塊id
        let chunkIds = data[0];
        //  獲取需要被動態加載模塊的依賴關係對象
        let moreModules = data[1]
        let chunkId
        let resolves = []
        // 循環判斷chunkIds裏對應的模塊內容是否已經完成加載
        for (let i = 0; i < chunkIds.length; i++) {
            chunkId = chunkIds[i]
            if (Object.prototype.hasOwnProperty.call(inStalledChunks, chunkId) && inStalledChunks[chunkId]) {
                //數組順序,resolve,reject,promise,這裏是已經加載,所以是0
                resolves.push(inStalledChunks[chunkId][0])
            }
            // 更新chunk狀態
            inStalledChunks[chunkId] = 0;
        }

        for (let moduleId in moreModules) {
            if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
                modules[moduleId] = moreModules[moduleId]
            }
        }

        while (resolves.length) {
            resolves.shift()()
        }
    }

    // 定義inStalledChunks 用於標識某個chunkId對應的chunk是否完成加載
    let inStalledChunks = {
        main: 0
    }

    // 定義jsonpScriptSrc實現src的處理
    function jsonpScriptSrc(chunkId) {
        return __webpack_require__.p + "" + chunkId + '.built.js'
    }

    // 定義e方法,用於實現 :實現jsonP異步加載,利用promise來實現異步加載操作
    __webpack_require__.e = function (chunkId) {
        // 定義一個數組用於存放promise
        let promises = [];
        // 獲取chunkId對應的chunk是否已經完成了加載
        let installedChunkData = inStalledChunks[chunkId]
        // 依據當前是否已完成加載的狀態來執行後續的邏輯
        if (installedChunkData !== 0) {
            if (installedChunkData) {
                // push一個完整的promise
                promises.push(installedChunkData[2])
            } else {
                // 執行加載操作
                let promise = new Promise((resolve, reject) => {
                    installedChunkData = inStalledChunks[chunkId] = [resolve, reject]
                })
                promises.push(installedChunkData[2] = promise)
                // 創建標籤
                let script = document.createElement('script')
                // 設置src
                script.src = jsonpScriptSrc(chunkId)
                // 寫入script標籤
                document.head.appendChild(script)
            }
        }

        // 執行promise
        return Promise.all(promises)
    }
user avatar columsys 頭像 weirdo_5f6c401c6cc86 頭像 nihaojob 頭像 niaonao 頭像 maogexiaodi 頭像 dingxi 頭像 yangyaya 頭像 lllllxt 頭像 minnanitkong 頭像 jinl9s27 頭像 ishy 頭像 imwty 頭像
16 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.