好程序员web前端教程分享js中的模块化二
admin
2023-02-17 10:00:02
0

好程序员web前端教程接下来降为大家继续分享js中的模块化知识
4.循环依赖
就是a依赖b,b依赖a,对于不同的规范也有不同的结果。
4.1CommonJS
对于node,每一个模块的exports={done:false}表示一个模块有没有加载完毕,经过一系列的加载最后全部都会变为true。 同步,从上到下,只输出已经执行的那部分代码 首先,我们写两个js用node跑一下:
//a.js
console.log('a.js')
var b = require('./b.js')
console.log(1)
//b.js
console.log('b.js')
var a = require('./a.js')
console.log(2)

//根据他的特点,require一个文件的时候,马上运行内部的代码,所以相当于
console.log('a.js')
console.log('b.js')
console.log(2)
console.log(1)
//输出是a.js、b.js、2、1
复制代码
加上export的时候:
//a.js
module.exports = {val:1}
var b = require('./b.js')
console.log(b.val)
module.exports = {val:2}
b.val = 3
console.log(b)

//b.js
module.exports = {val:1}
var a = require('./a.js')
console.log(a.val)
module.exports = {val:2}
a.val = 3
console.log(a)

//1.在a.js暴露出去一个对象module.exports = {val:1}
//2.require了b,来到b,运行b脚本
//3.b的第一行,把{val:1}暴露出去,引入刚刚a暴露的{val:1},打印a.val的结果肯定是1
//4.重新暴露一次,是{val:2},然后做了一件多余的事情,改a.val为3(反正是拷贝过的了怎么改都不会影响a.js),毫无疑问打印出{ val: 3 }
//5.回到a,继续第三行,打印b.val,因为b暴露的值是2,打印2
//6.继续再做一件无意义的事情,打印{ val: 3 }
复制代码
解决办法:代码合理拆分
4.2ES6模块
ES6模块是输出值的引用,是动态引用,等到要用的时候才用,因此可以完美实现相互依赖,在相互依赖的a.mjs和b.mjs,执行a的时候,当发现import马上进入b并执行b的代码。当在b发现了a的时候,已经知道从a输入了接口来到b的,不会回到a。但是在使用的过程中需要注意,变量的顺序。
如果是单纯的暴露一个基本数据类型,当然会报错not defined。 因为函数声明会变量提升,所以我们可以改成函数声明(不能用函数表达式)
//a.mjs
import b from './b'
console.log(b())
function a(){return 'a'}
export default a
//b.mjs
import a from './a'
console.log(a())
function b(){return 'b'}
export default b
复制代码
4.3 require
我们一般使用的时候,都是依赖注入,如果是有循环依赖,那么可以直接利用require解决
define('a',['b'],function(b){
//dosomething
});
define('b',['a'],function(a){
//dosomething
});
//为了解决循环依赖,在循环依赖发生的时候,引入require:
define('a',['b','require'],function(b,require){
//dosomething
require('b')
});
复制代码
4.4 sea
循环依赖,一般就是这样
//a.js
define(function(require, exports, module){
var b = require('./b.js');
//......
});
//b.js
define(function(require, exports, module){
var a = require('./a.js');
//......
});
复制代码
而实际上,并没有问题,因为sea自己解决了这个问题: 一个模块有几种状态:
'FETCHING': 模块正在下载中 'FETCHED': 模块已下载 'SAVED': 模块信息已保存 'READY': 模块的依赖项都已下载,等待编译 'COMPILING':模块正在编译中 'COMPILED': 模块已编译
步骤:
1.模块a下载并且下载完成FETCHED
2.编译a模块(执行回调函数)
3.遇到了依赖b,b和自身没有循环依赖,a变成SAVED
4.模块b下载并且下载完成FETCHED
5.b遇到了依赖a,a是SAVED,和自身有循环依赖,b变成READY,编译完成后变成COMPILED
6.继续回到a,执行剩下的代码,如果有其他依赖继续重复上面步骤,如果所有的依赖都是READY,a变成READY
7.继续编译,当a回调函数部分所有的代码运行完毕,a变成COMPILED
对于所有的模块相互依赖的通用的办法,将相互依赖的部分抽取出来,放在一个中间件,利用发布订阅模式解决
5.webpack是如何处理模块化的
假设我们定义两个js:app.js是主入口文件,a.js、b.js是app依赖文件,用的是COMMONJS规范 webpack首先会从入口模块app.js开始,根据引入方法require把所有的模块都读取,然后写在一个列表上:
var modules = {
'./b.js': generated_b,
'./a.js': generated_a,
'./app.js': generatedapp
}
复制代码
'generated
'+name是一个IIFE,每个模块的源代码都在里面,不会暴露内部的变量。比如对于没有依赖其他模块的a.js一般是这样,没有变化:
function generated_a(module, exports, webpack_require) {
// ...a的全部代码
}
复制代码
对于app.js则不一样了:
function generated_app(module, exports, webpack_require) {
var a_imported_module = webpack_require('./a.js');
var b_imported_module =
webpack_require
('./b.js');
a_imported_module['inc']();
b_imported_module['inc']();
}
复制代码
webpack_require就是require、exports、import这些的具体实现,够动态地载入模块a、b,并且将结果返回给app
对于webpack_require,大概是这样的流程
var installedModules = {};//保存已经加载完成的模块
function webpack_require(moduleId) {
if (installedModules[moduleId]) {//如果已经加载完成直接返回
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {//如果是第一次加载,则记录在表上
i: moduleId,
l: false,//没有下载完成
exports: {}
};
//在模块清单上面读取对应的路径所对应的文件,将模块函数的调用对象绑定为module.exports,并返回
modules[moduleId].call(module.exports, module, module.exports,webpack_require);
module.l = true;//下载完成
return module.exports;
}
复制代码
对于webpack打包后的文件,是一个庞大的IIFE,他的内容大概是这样子:
(function(modules) {
var installedModules = {};
function
webpack_require
(moduleId) { /.../}
webpack_require.m = modules;//所有的文件依赖列表
webpack_require
.c = installedModules;//已经下载完成的列表
webpack_require.d = function(exports, name, getter) {//定义模块对象的getter函数
if(!
webpack_require
.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
webpack_require.n = function(module) {//当和ES6模块混用的时候的处理
var getter = module && module.
esModule ?//如果是ES6模块用module.default
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };//是COMMONJS则继续用module
__webpack_require
.d(getter, 'a', getter);
return getter;
};
webpack_require.o = function(object, property) { //判断是否有某种属性(如exports)
return Object.prototype.hasOwnProperty.call(object, property);
};
webpack_require
.p = "";//默认路径为当前
return webpack_require(webpack_require.s = 0);//读取第一个模块
})
/****/
//IIFE第二个括号部分
([
(function(module, exports, webpack_require) {
var a =
webpack_require
(1);
var b = __webpack_require__(2);
//模块app代码
}),

(function(module, exports, webpack_require) {
//模块a代码
module.exports = ...
}),
(function(module, exports,
webpack_require
) {
//模块b代码
module.exports = ...
})
]);
复制代码
如果是ES6模块,处理的方法也不一样。还是假设我们定义两个js:app.js是主入口文件,a.js、b.js是app依赖文件。
(function(modules) {
//前面这段是一样的
})
([
(function(module, webpack_exports, webpack_require) {//入口模块
Object.defineProperty(webpack_exports, "esModule", { value: true });
var __WEBPACK_IMPORTED_MODULE_0
m = webpack_require(1);
var
WEBPACK_IMPORTED_MODULE_1m = webpack_require(2);
Object(
WEBPACK_IMPORTED_MODULE_0
m["a"])();//用object包裹着,使得其他模块export的内容即使是基本数据类型,也要让他变成一个引用类型
Object(
WEBPACK_IMPORTED_MODULE_1m["b"])();

}),
(function(module, webpack_exports, webpack_require) {
webpack_exports["a"] = a;//也就是export xxx
//....
}),
(function(module,
webpack_exports
, webpack_require) {
webpack_exports
["b"] = b;
//....
})
]);

相关内容

热门资讯

巴拿马外长喊话访华团:尊重中国... 【文/观察者网 柳白】据香港英文媒体《南华早报》报道,数名巴拿马议员组成的代表团抵达中国访问之际,巴...
华帝燃气灶自动熄火什么原因 原因:热敏针出现故障,检查灶眼,看中间的火焰能不能烧到探针,烧到探针才能定住火,在点火的时候,长按几...
燃气灶一直打火滴滴响然后熄火 原因可能是在刚打开的时候马上熄火了,这种情况比较复杂,建议首先检查燃气灶出火的地方是否堵塞,对出火口...
煤气灶一直打火嗒嗒嗒响怎么修理 问题:煤气灶一直打火嗒嗒嗒响怎么修理回答:1、有时候煤气灶的电路出现了接触不良,就会导致在使用过程当...
天然气灶打不着火一直滴滴响 1、没有燃气,在碰到天然气灶打不着火时,首先要查看是否还有燃气。2、电池没电,发现点不着火而且没有哒...
燃气打不着火一直滋滋响就是不着 点火针位置不正确,只要调整点火针就可以了。托起燃气灶拧开镙丝钉,打开密封盖,揭起钢化玻璃面板。安装上...
亲绿民调中柯志恩追近13%,蓝... 海峡导报综合报道 岛内亲绿媒体5日公布高雄市长选举民调,民进党民代赖瑞隆以47%支持度暂时领先国民党...
拒绝美国干涉,巴拿马议员抵华交... “我们是一个自由且拥有主权的国家……我们想去哪里,就去哪里。”正在中国访问的巴拿马民主革命党议员哈伊...
高市下跪了,但更值得警惕 我相信,中国、韩国等很多亚洲国家的朋友,看到这一幕,心头翻涌的不是感慨,更多是气愤。日本首相高市早苗...
万邦德重磅创新药再获突破! 斩... 5月5日,万邦德(002082)在研创新药传出重磅利好,全资子公司万邦德制药集团有限公司(下称“万邦...