欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

webpack是如何實(shí)現(xiàn)模塊化加載的方法

 更新時間:2019年11月06日 09:37:54   作者:ztMin  
這篇文章主要介紹了webpack是如何實(shí)現(xiàn)模塊化加載的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

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

同步加載如下:

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

異步加載如下:

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

webpacks實(shí)現(xiàn)的啟動函數(shù),直接將入口程序module傳入啟動函數(shù)內(nèi),并緩存在閉包內(nèi),如下:

(function(modules){
  ......
  // 加載入口模塊并導(dǎo)出(實(shí)現(xiàn)啟動程序)
  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在實(shí)現(xiàn)模塊管理上不管服務(wù)端還是客戶端大致是一樣,主要由installedChunks記錄已經(jīng)加載的chunk,installedModules記錄已經(jīng)執(zhí)行過的模塊,具體如下:

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

不管是服務(wù)端還是客戶端同步加載的方法都一樣,主要是檢測installedModules中是否已經(jīng)緩存有要加載的module,有則直接返回,否則就創(chuàng)建一個新的module,并執(zhí)行返回module.exports,具體實(shí)現(xiàn)如下:

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

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

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

// 編譯后的異步加載方法
__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原理進(jìn)行加載資源,將chunk內(nèi)容([chunkIds, modules])存到全局的webpackJsonp數(shù)組中,并改造webpackJsonp的push方法實(shí)現(xiàn)監(jiān)聽chunk加載完成事件。具體實(shí)現(xiàn)如下:

// 編譯后的異步加載方法
__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');
    });
  })
}]);

// 加載成功的回調(diào)函數(shù)
function webpackJsonpCallback(data) {
  var chunkIds = data[0];
  var moreModules = data[1];
  
  // 將本次加載回來的 chunk 標(biāo)記為加載完成狀態(tài),并執(zhí)行回調(diào)
  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成功回調(diào)添加到要執(zhí)行的隊列中
    }
    installedChunks[chunkId] = 0; // 將chunk標(biāo)記為加載完成
  }
  // 將本次加載回來的 module 添加到全局的 modules 對象
  for(moduleId in moreModules) {
    if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
      modules[moduleId] = moreModules[moduleId];
    }
  }
  // 判斷 webpackJsonp 數(shù)組原始的push方法是否存在,存在則將數(shù)據(jù)追加到webpackJsonp中
  if(parentJsonpFunction) parentJsonpFunction(data);
  // 執(zhí)行所有 chunk 回調(diào)
  while(resolves.length) {
    resolves.shift()();
  }
};

// 加載完成監(jiān)聽方法的實(shí)現(xiàn)
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 時表示已經(jīng)安裝完成
    if(installedChunkData) { // 加載中
      promises.push(installedChunkData[2]);
    } else {
      // 創(chuàng)建一個回調(diào)的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) { // 加載完成回調(diào)
        // 避免IE內(nèi)存泄漏。
        script.onerror = script.onload = null;
        clearTimeout(timeout); // 關(guān)閉超時定時器
        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(){ // 設(shè)置超時定時器
        onScriptComplete({ type: 'timeout', target: script });
      }, 120000);
      script.onerror = script.onload = onScriptComplete; // 設(shè)置加載完成回調(diào)
      document.head.appendChild(script);
    }
  }
  return Promise.all(promises);
};

更多可以查看編譯后的代碼 客戶端、服務(wù)端

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JavaScript中判斷函數(shù)、變量是否存在

    JavaScript中判斷函數(shù)、變量是否存在

    這篇文章主要介紹了JavaScript中判斷函數(shù)、變量是否存在,本文給出了多個判斷函數(shù)是否存在的方法,并分別給出代碼實(shí)例,需要的朋友可以參考下
    2015-06-06
  • javascript 圖片輪換 函數(shù)化繼承

    javascript 圖片輪換 函數(shù)化繼承

    一直讓我困擾的是,我不知道如何去讓這個效果 自動播放,或者費(fèi)了很多周折。這可能叫初始化。
    2010-05-05
  • uniapp實(shí)現(xiàn)釘釘掃碼登錄示例代碼

    uniapp實(shí)現(xiàn)釘釘掃碼登錄示例代碼

    由于uniapp暫無釘釘授權(quán)登錄所以本文將釘釘掃碼登錄作為網(wǎng)頁嵌入uniapp,最終實(shí)現(xiàn)釘釘掃碼登錄app,本文通過實(shí)例代碼給大家介紹uniapp釘釘掃碼登錄功能,感興趣的朋友一起看看吧
    2021-12-12
  • JS實(shí)現(xiàn)定時自動消失的彈出窗口

    JS實(shí)現(xiàn)定時自動消失的彈出窗口

    這篇文章介紹了JS實(shí)現(xiàn)定時自動消失的彈出窗口,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • JS 控制小數(shù)位數(shù)的實(shí)現(xiàn)代碼

    JS 控制小數(shù)位數(shù)的實(shí)現(xiàn)代碼

    上網(wǎng)查一查的確存在這種Bug,除了位數(shù)上控制之外也沒什么也好的方法(希望高手能提出其它思路)。
    2011-08-08
  • JavaScript繼承模式粗探

    JavaScript繼承模式粗探

    之前提到了JS中比較簡單的設(shè)計模式,在各種設(shè)計模式中被最常使用的工具之一就是原型鏈的繼承。作為OOP的特質(zhì)之一——繼承,今天主要談?wù)凧S中比較簡單的繼承方法
    2016-01-01
  • ie6下png圖片背景不透明的解決辦法使用js實(shí)現(xiàn)

    ie6下png圖片背景不透明的解決辦法使用js實(shí)現(xiàn)

    我們時常在使用png圖片的時候,在ie6下發(fā)生背景不透明的問題,解決的方法實(shí)在是太多了,下面給大家介紹下一個js解決的方式,感興趣的朋友可以了解下的
    2013-01-01
  • 微信小程序裁剪頭像插件使用方法詳解

    微信小程序裁剪頭像插件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了微信小程序裁剪頭像插件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • JavaScript實(shí)現(xiàn)大數(shù)的運(yùn)算

    JavaScript實(shí)現(xiàn)大數(shù)的運(yùn)算

    js的'MAX_SAFE_INTEGER'是9007199254740991,而'MIN_SAFE_INTEGER'為-9007199254740991,那么如何實(shí)現(xiàn)一些特別大的數(shù)目相加?今天我們就來探討下
    2014-11-11
  • JavaScript-html標(biāo)題滾動效果的簡單實(shí)現(xiàn)

    JavaScript-html標(biāo)題滾動效果的簡單實(shí)現(xiàn)

    下面小編就為大家?guī)硪黄狫avaScript-html標(biāo)題滾動效果的簡單實(shí)現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09

最新評論