commonjs是同步模块加载方式,因此其加载完成后才能执行下面的动作,require第一次加载完该脚本,就会在内存中生成一个对象,类似以:
{
id: '...',
exports: { ... },
loaded: true,
...
}
接着运行脚本,从别处引用此模块时,可以引用其exports出来的内容。当模块第二次引用时不会去重复加载,而是执行上次缓存的。
若出现循环引用,就只执行已经输出的(exports)部分,其他的未导出的不用管。
例如a.js和b.js相互引用:
a.js内容为:
exports.done = false;
var b = require('./b.js');
exports.hello = false;
console.log(`在a中b.done的值为:`+b.done);
exports.done = true;
b.js内容为:
exports.done = false;
var a = require('./a.js');
console.log(`在b中a.done的值为:`+a.done);
console.log(`在b中a.hello的值为:`+a.hello);
exports.done = true;
在main.js引用a和b
var a = require('./a.js');
var b = require('./b.js');
console.log(a.done,b.done,b.hello);
var a1 = require('./a.js');
var b1 = require('./b.js');
console.log(a1.done,b1.done,b.hello);
解释:
在a.js中,第一行,导出其done值为false,第二行引用b.js,此时进入b.js中,第一行导出其done值为false,第二行引用a.js,此时进入a.js中,而a.js只执行了两行,只输出了一个值即done为false;所以b.js而 第二行的a只能引用到done值,hello值为undefined。所以b.js输出
在b中a.done的值为:false
在b中a.hello的值为:undefined
b.js执行完成后,其done值为true,然后继续a.js第三行,第四行输出:
在a中b.done的值为:true
此时a中done为true,hello为false,而b.js只能引用a中done的值。
所以console.log(a.done,b.done,b.hello);
这行输出:true true undefined
,而再次引用a和b时,不会再次执行。所以:
var a1 = require('./a.js');
var b1 = require('./b.js');
console.log(a1.done,b1.done,b.hello);
只会输出:true true undefined
。
若将a.js变成:
exports.done = false;
setTimeout(function () {
exports.done = 'anotherDone';
},5000);
var b = require('./b.js');
exports.hello = false;
console.log(`在a中b.done的值为:`+b.done);
exports.done = true;
main.js变成:
var a = require('./a.js');
var b = require('./b.js');
console.log(a.done,b.done,b.hello);
var a1 = require('./a.js');
var b1 = require('./b.js');
setTimeout(function () {
console.log(a1.done,b1.done,b.hello);
},6000);
输出为:
在b中a.done的值为:false
在b中a.hello的值为:undefined
在a中b.done的值为:true
true true undefined
anotherDone true undefined
最后一行输出a1.done为anotherDone因为exports在内存中是一个对象形成存在的,a1中存储的是对他的引用,所以,a.js改变done后能通过a1体现出来。
ES6中对模块的引用不像commonjs中那样必须执行require进来的模块,而只是保存一个模块的引用而已,因此,即使是循环引用也不会出错。
even.js
import { odd } from './odd'
export var counter = 0;
export function even(n) {
counter++;
return n === 0 || odd(n - 1);
}
export function even2() {
console.log(1234);
}
odd.js
import { even, even2 } from './even';
export function odd(n) {
even2();
return n != 0 && even(n - 1);
}
main.js
require('babel-core/register');
var even = require('./even');
even.even(6);
console.log(even.counter);
运行main.js输出:
1234
1234
1234
4
requirejs中出现循环引用时,可将引用的模块用局部require进行包裹以避免错误出现:
a.js
define(['require'],function (require) {
console.log('this is in a ');
var b = require(['b'],function () {
console.log('in a b.name:'+b.name);
});
function af() {
console.log('this is af')
}
return {
name:'aname',
af:af
};
});
b.js
define(['require'],function (require) {
console.log('this is in b ');
var a = require(['a'],function () {
console.log('in b a.name:'+a.name);
});
function bf() {
console.log('this is bf')
}
return {
name:'bname',
bf:bf
};
});
main.js
require(['a'],function (a) {
a.af();
});
输出:
this is in a
this is af
this is in b
in a b.name:localRequire
in b a.name:localRequire