commonjs
当有循环 require() 调用时,模块在返回时可能尚未完成执行。
考虑这种情况:
a.js:
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js:
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js:
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
当 main.js 加载 a.js 时,a.js 依次加载 b.js。 此时,b.js 尝试加载 a.js。 为了防止无限循环,将 a.js 导出对象的未完成副本返回给 b.js 模块。 然后 b.js 完成加载,并将其 exports 对象提供给 a.js 模块。
到 main.js 加载这两个模块时,它们都已完成。 因此,该程序的输出将是:
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true
esmodule
代码示例:
main.js
import a from './a'
console.log(a)
a.js
console.log('执行a')
import b from './b'
console.log(b)
console.log('导入b之后')
export default '我是a模块'
b.js
console.log('执行b')
import a from './a'
console.log(a)
console.log('导入a之后')
export default '我是b模块'
执行main.js,输出结果:
// main.js里import了a,先进到a解析
// import语句提前解析,a里import了b,所以暂停a的解析,进到b解析
// b里import了a,但a此时还未执行完,拿到的a值是undefined,然后往下继续解析b
b.js:1 执行b
b.js:3 undefined
b.js:4 导入a之后
// b解析完并拿到了b的导出结果,开始回到a里继续往下解析
a.js:1 执行a
a.js:3 我是b模块
a.js:4 导入b之后
// a解析完后,回到main.js解析执行
main.js:2 我是a模块
区别
commonjs导出的是模块的值的拷贝,esmodule导出模块引用,解析完a之后esmodule引入a的值会跟着a变,而commonjs中a的值不变