循环引用的基本表现是:a 文件引入了 b 文件的模块,b 文件引入了 a 文件的模块。也有多个文件的循环引用,比如 a 引入 b 模块,b 引入 c 模块,c 引入 a 模块。
理论上循环引用会导致栈溢出,但并非所有循环引用都会导致栈溢出,比如下例,执行 webpack 打包出的文件,会依次打印:undefined、b、a
什么情况下才会导致栈溢出呢?在导出模块中相互调用对方,才会导致栈溢出。比如下面的例子:
看看打包出的代码(去除了部分无关代码):
/******/ (function(modules) {
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 1);
/******/ })
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(2);
__webpack_exports__["a"] = (val => {
Object(__WEBPACK_IMPORTED_MODULE_0__b__["a" /* default */])('a')
console.log(val)
});
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);
// 入口文件
Object(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */])(1)
/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);
__webpack_exports__["a"] = (val => {
Object(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */])('b')
console.log(val)
});
/***/ })
]);
执行顺序:
- 执行模块 1,执行
__webpack_require__(0)
- 执行模块 0,执行
__webpack_require__(2)
- 执行模块 2,模块 2 完成安装(b.js),导出一个函数
- 继续执行模块 0,模块 0 完成安装(a.js),导出一个函数
- 继续执行模块 1,执行
(_WEBPACK_IMPORTED_MODULE_0__a__["a"])(1)
,__WEBPACK_IMPORTED_MODULE_0__a_
拿到的是对__webpack_require__(0)
的引用,即:
{
a: val => {
Object(__WEBPACK_IMPORTED_MODULE_0__b__["a" ])('a')
console.log(val)
}
}
调用 WEBPACK_IMPORTED_MODULE_0__a__["a"]
又会执行 __WEBPACK_IMPORTED_MODULE_0__b__["a"]
,_WEBPACK_IMPORTED_MODULE_0__b_
是对 __webpack_require__(2)
的引用,即:
{
a: val => {
Object(__WEBPACK_IMPORTED_MODULE_0__a__["a"])('b')
console.log(val)
}
}
相当于:
f1 = () => f2();
f2 = () => f1();
f1();
既然 webpack 不会因为循环引用导致打包出错,也就意味着项目中可能隐藏着未知的循环引用,怎么才能知道是否存在循环引用呢?有一个插件可以解决这个问题:circular-dependency-plugin
。
热门评论
大神 再掘金也看见你的专栏 什么时候出视频课程 我买