中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

webpack是如何實現模塊化加載的

發布時間:2020-05-18 03:40:45 來源:網絡 閱讀:1175 作者:dolunbu 欄目:web開發

webpack支持的模塊規范有?AMD?、CommonJS、ES2015 import?等規范。不管何種規范大致可以分為同步加載和異步加載兩種情況。本文將介紹webpack是如何實現模塊管理和加載。

同步加載如下:

import?a?from?'./a';
console.log(a);

異步加載如下:

import('./a').then(a?=>?console.log(a));

webpacks實現的啟動函數,直接將入口程序module傳入啟動函數內,并緩存在閉包內,如下:

(function(modules){
......
//?加載入口模塊并導出(實現啟動程序)
return?__webpack_require__(__webpack_require__.s?=?0);
})({
0:?(function(module,?__webpack_exports__,?__webpack_require__)?{
module.exports?=?__webpack_require__(/*!?./src/app.js?*/"./src/app.js");
})
})

webpack在實現模塊管理上不管服務端還是客戶端大致是一樣,主要由installedChunks記錄已經加載的chunk,installedModules記錄已經執行過的模塊,具體如下:

/**
*?module?緩存器
*?key?為?moduleId?(一般為文件路徑)
*?value?為?module?對象?{i:?moduleId,?l:?false,?exports:?{}}
*/
var?installedModules?=?{};
/**
*?chunks加載狀態記錄器
*?key?一般為?chunk?索引
*?value?undefined:未加載?0:已經加載?(客戶端特有?null:?準備加載?[resolve,?reject]:?加載中)
*/
var?installedChunks?=?{
"app":?0
}

不管是服務端還是客戶端同步加載的方法都一樣,主要是檢測installedModules中是否已經緩存有要加載的module,有則直接返回,否則就創建一個新的module,并執行返回module.exports,具體實現如下:

//?編譯后的同步加載
__webpack_require__(/*!?./src/app.js?*/"./src/app.js");

//?加載模塊的方法,即require方法
function?__webpack_require__(moduleId)?{
//?檢查當前的module是否已經存在緩存中
if(installedModules[moduleId])?{
return?installedModules[moduleId].exports;?//?直接返回已緩存的?module.exports
}
//?創建一個新的?module,?并添加到緩存中
var?module?=?installedModules[moduleId]?=?{
i:?moduleId,
l:?false,?//?是否已經加載
exports:?{}?//?暴露的對象
};
//?執行當前?module?的方法
modules[moduleId].call(module.exports,?module,?module.exports,?__webpack_require__);
//?標記?module?加載完成狀態
module.l?=?true;
//?返回?module?暴露的?exports?對象
return?module.exports;
}

服務端的異步加載是通過node的require方法加載chunk并返回一個promises對象。所有chunk都是暴露出ids和modules對象,具體實現如下:

//?編譯后的異步加載方法
__webpack_require__.e(/*!?import()?*/?0).then(__webpack_require__.bind(null,?/*!?./c.js?*/?"./src/c.js"))

//?chunk?0?代碼如下(即0.js的代碼)
exports.ids?=?[0];
exports.modules?=?{
"./src/c.js":?(function(module,?__webpack_exports__,?__webpack_require__)?{
"use?strict";
__webpack_require__.r(__webpack_exports__);
__webpack_exports__["default"]?=?(function?()?{
console.log('c');
})
})
}

//?異步加載模塊方法
__webpack_require__.e?=?function?requireEnsure(chunkId)?{
var?promises?=?[];
if(installedChunks[chunkId]?!==?0)?{
var?chunk?=?require("./"?+?({}[chunkId]||chunkId)?+?".js");
var?moreModules?=?chunk.modules,?chunkIds?=?chunk.ids;
for(var?moduleId?in?moreModules)?{
modules[moduleId]?=?moreModules[moduleId];
}
for(var?i?=?0;?i?<?chunkIds.length;?i++)
installedChunks[chunkIds[i]]?=?0;
}
return?Promise.all(promises);
}

客戶端的異步加載是通過JSONP原理進行加載資源,將chunk內容([chunkIds, modules])存到全局的webpackJsonp數組中,并改造webpackJsonp的push方法實現監聽chunk加載完成事件。具體實現如下:

//?編譯后的異步加載方法
__webpack_require__.e(/*!?import()?*/?0).then(__webpack_require__.bind(null,?/*!?./c.js?*/?"./src/c.js"))

//?chunk?0?代碼如下(即0.js的代碼)
(window["webpackJsonp"]?=?window["webpackJsonp"]?||?[]).push([[0],{
"./src/c.js":?(function(module,?__webpack_exports__,?__webpack_require__)?{
"use?strict";
__webpack_require__.r(__webpack_exports__);
__webpack_exports__["default"]?=?(function?()?{
console.log('c');
});
})
}]);

//?加載成功的回調函數
function?webpackJsonpCallback(data)?{
var?chunkIds?=?data[0];
var?moreModules?=?data[1];

//?將本次加載回來的?chunk?標記為加載完成狀態,并執行回調
var?moduleId,?chunkId,?i?=?0,?resolves?=?[];
for(;i?<?chunkIds.length;?i++)?{
chunkId?=?chunkIds[i];
if(Object.prototype.hasOwnProperty.call(installedChunks,?chunkId)?&&?installedChunks[chunkId])?{
resolves.push(installedChunks[chunkId][0]);?//?將chunk成功回調添加到要執行的隊列中
}
installedChunks[chunkId]?=?0;?//?將chunk標記為加載完成
}
//?將本次加載回來的?module?添加到全局的?modules?對象
for(moduleId?in?moreModules)?{
if(Object.prototype.hasOwnProperty.call(moreModules,?moduleId))?{
modules[moduleId]?=?moreModules[moduleId];
}
}
//?判斷?webpackJsonp?數組原始的push方法是否存在,存在則將數據追加到webpackJsonp中
if(parentJsonpFunction)?parentJsonpFunction(data);
//?執行所有?chunk?回調
while(resolves.length)?{
resolves.shift()();
}
};

//?加載完成監聽方法的實現
var?jsonpArray?=?window["webpackJsonp"]?=?window["webpackJsonp"]?||?[];
var?oldJsonpFunction?=?jsonpArray.push.bind(jsonpArray);
jsonpArray.push?=?webpackJsonpCallback;
jsonpArray?=?jsonpArray.slice();
for(var?i?=?0;?i?<?jsonpArray.length;?i++)?webpackJsonpCallback(jsonpArray[i]);
var?parentJsonpFunction?=?oldJsonpFunction;

//?異步加載模塊方法
__webpack_require__.e?=?function?requireEnsure(chunkId)?{
var?promises?=?[];
var?installedChunkData?=?installedChunks[chunkId];
if(installedChunkData?!==?0)?{?//?0?時表示已經安裝完成
if(installedChunkData)?{?//?加載中
promises.push(installedChunkData[2]);
}?else?{
//?創建一個回調的Promise,并將Promise緩存到installedChunks中
var?promise?=?new?Promise(function(resolve,?reject)?{
installedChunkData?=?installedChunks[chunkId]?=?[resolve,?reject];
});
promises.push(installedChunkData[2]?=?promise);

var?script?=?document.createElement('script');
var?onScriptComplete;
script.charset?=?'utf-8';
script.timeout?=?120;
if?(__webpack_require__.nc)?{
script.setAttribute("nonce",?__webpack_require__.nc);
}
script.src?=?jsonpScriptSrc(chunkId);

var?error?=?new?Error();
onScriptComplete?=?function?(event)?{?//?加載完成回調
//?避免IE內存泄漏。
script.onerror?=?script.onload?=?null;
clearTimeout(timeout);?//?關閉超時定時器
var?chunk?=?installedChunks[chunkId];
if(chunk?!==?0)?{?//?未加載完成
if(chunk)?{?//?加載中
var?errorType?=?event?&&?(event.type?===?'load'???'missing'?:?event.type);
var?realSrc?=?event?&&?event.target?&&?event.target.src;
error.message?=?'Loading?chunk?'?+?chunkId?+?'?failed.\n('?+?errorType?+?':?'?+?realSrc?+?')';
error.name?=?'ChunkLoadError';
error.type?=?errorType;
error.request?=?realSrc;
chunk[1](error);
}
installedChunks[chunkId]?=?undefined;
}
};
var?timeout?=?setTimeout(function(){?//?設置超時定時器
onScriptComplete({?type:?'timeout',?target:?script?});
},?120000);
script.onerror?=?script.onload?=?onScriptComplete;?//?設置加載完成回調
document.head.appendChild(script);
}
}
return?Promise.all(promises);
};


文章同步發布:?https://www.geek-share.com/detail/2784034803.html

參考文章:

詳解webpack + react + react-router 如何實現懶加載

Webpack2 + Vue2 + Vue-Router2 如何實現懶加載?

?


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安吉县| 神木县| 施秉县| 仙居县| 广丰县| 田林县| 柞水县| 咸阳市| 怀仁县| 永年县| 江川县| 高雄市| 台山市| 余干县| 霍山县| 凌海市| 加查县| 南阳市| 桂阳县| 新民市| 万安县| 莱州市| 林州市| 莆田市| 射阳县| 富川| 乡城县| 错那县| 措勤县| 惠东县| 海门市| 台东市| 饶平县| 板桥市| 深圳市| 麦盖提县| 资源县| 内江市| 忻州市| 宣威市| 上林县|