Cyclic loading of modules
If a circular loading of modules occurs, i.e. A loads B which in turn loads A, then B will load an incomplete version of A.
// a.js
exports.x = 'a1';
console.log('a.js ', require('./b.js').x);
exports.x = 'a2';
// b.js
exports.x = 'b1';
console.log('b.js ', require('./a.js').x);
exports.x = 'b2';
// main.js
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);
The above code is three JavaScript files. Among them, a.js loads b.js, which in turn loads a.js. At this time, Node returns an incomplete version of a.js, so the execution result is as follows.
Modify main.js and load a.js and b.js again.
// main.js
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);
Execute the above code, the result is as follows.
In the above code, when a.js and b.js are loaded for the second time, the exports property will be directly read from the cache, so the console.log statements inside a.js and b.js will not be executed.
require.main
require
The method has an main
attribute that can be used to determine whether the module executes directly or is called to execute .
When executed directly ( node module.js
), the require.main
attribute points to the module itself.
When the call is executed (by require
loading the script), the above expression returns false.
Module loading mechanism
The loading mechanism of CommonJS modules is that the input is a copy of the value that is output . That is, once a value is output , changes within the module cannot affect this value . See the example below.
Below is a module file lib.js
.
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, };
The above code outputs the internal variable counter
and the internal method that overwrites this variable incCounter
.
Then, load the above module.
// main.js var counter = require('./lib').counter; var incCounter = require('./lib').incCounter; console.log(counter); // 3 incCounter(); console.log(counter); // 3
The above code shows that counter
after output, lib.js
changes inside the module will not be affected counter
.
The internal processing flow of require
require
Commands are the commands in the CommonJS specification to load other modules. It's not actually a global command, but a command that points to the current module , which in turn calls Node's internal commands . module.require
Module._load
上面的第4步,采用module.compile()
执行指定模块的脚本,逻辑如下。
The above steps 1 and 2, require
functions and their auxiliary methods are mainly as follows.
Once the require
function is ready, the entire script content to be loaded is put into a new function, which can avoid polluting the global environment. The parameters of this function include require
, module
, exports
, and a few others.
(function (exports, require, module, __filename, __dirname) { // YOUR CODE INJECTED HERE! });
Module._compile
The method is executed synchronously , so it will not return the value to the user until Module._load
it finishes executing .module.exports