The CommonJS module specification imports modules using the require statement. Module. exports exports modules that export a copy of the output value, meaning that once the value is exported, changes in the value inside the module are not heard.

The ES6 module specification uses the import statement to import the module, the export statement to export the module, and the output is a reference to the value. ES6 module is different from CommonJS. When the module load command import is encountered, it does not execute the module, but only generates a dynamic read-only reference. When the value is really needed, the value will be used in the module.

What is the difference between the CommonJS and ES6 module specifications in how modules are loop-loaded?

Cyclic loading means that the execution of script A depends on script B, and script B depends on script A.

1. Loading principle of CommonJS module

The CommonJS module is a script file that executes the entire script when it is first loaded by the require command and then generates a description object for the module in memory.

{
    id: ' ', // module name, unique exports: {// module exports each interface... }, loaded:true// Whether the script of the module is finished executing... }Copy the code

When the module is used later, it is evaluated in the exports property of the object. Even if the require command is executed again, the module is not executed again, but is evaluated in the cache.

CommonJS modules are load-time, meaning that script code is executed at require. Once a module is “looping”, only the parts that have been executed are printed, and the parts that have not been executed are not printed.

Case description:

The case is from Node official description: nodejs.org/api/modules…

//a.js
exports.done = false;

var b = require('./b.js');
console.log('in a.js, b.tone = %j', b.done);

exports.done = true;
console.log('A.js executed! ')
Copy the code
//b.js
exports.done = false;

var a = require('./a.js');
console.log('in b.js, a. tone = %j', a.done);

exports.done = true;
console.log('B.js executed! ')
Copy the code
//main.js
var a = require('./a.js');
var b = require('./b.js');

console.log('in main.js, a.tone = %j, b.tone = %j', a.done, b.done);
Copy the code

The following output is displayed:

Nodemain. js in b.js, a.dot =falseB. Js execution complete! In A. js, B. Tone =trueA. Js Execution complete! In main.js, a.tone =true, b.done = true
Copy the code

The order of JS code execution is as follows:

1) a.js is loaded in main.js first, script A outputs the done variable with a value of false, and then script B is loaded. The code of a stops execution, and the execution will continue after the execution of script B is completed.

2) The second line of B. js will load A. js, when cyclic loading occurs, the system will fetch the value of the exports property of the corresponding object of the MODULE A. js, because the execution of A. js is not complete, only the executed part can be retrieved from the exports property, the unexecuted part is not returned, so the retrieved value is not the last value.

3) a.js executes only one line of code, exports.done = false; So for B. js, require A. js prints only one variable done, with a value of false. Go to console.log(‘ in B.js, a.tone = %j’, a.tone); The console prints:

In B. js, A. Tone =false
Copy the code

4) b.js continues with the done variable set to true, console.log(‘b.js finished! ‘), when all the execution is completed, the execution power is returned to A. JS. At this point the console outputs:

B. Js execution complete!Copy the code

Console. log(‘ in a.js, b.tone = %j’, b.tone); The console prints:

In A. js, B. Tone =true
Copy the code

6) A.js continues with the done variable set to true until a.js completes execution.

A. Js Execution complete!Copy the code

7) The second line in main.js will not execute b.js again, and directly output the cached result. Final console output:

In main.js, a.tone =true, b.done = true
Copy the code

Conclusion:

1) in B. js, the execution of a.js is not complete, only the first line is executed, so in cyclic loading, only the executed part is output.

2) The second line of main.js will not be executed again, but will output the execution result of cache B.js. exports.done = true;

2. Cyclic loading of ES6 modules

ES6 module is different from CommonJS in essence. ES6 module dynamically references exported variables, methods and objects. When the module loading command import is encountered, it does not execute the module, but only generates a reference to the loaded module.

Case description:

//even.js
import {odd} from './odd';

var counter = 0;
export function even(n){
    counter ++;
    console.log(counter);
    
    return n == 0 || odd(n-1);
}
Copy the code
//odd.js
import {even} from './even.js';

export function odd(n){
    returnn ! = 0 && even(n-1); }Copy the code
//index.js
import * as m from './even.js';

var x = m.even(5);
console.log(x);

var y = m.even(4);
console.log(y);
Copy the code

Execute index.js, and the output is as follows:

babel-node index.js

1
2
3
false
4
5
6
true
Copy the code

You can see that the value of counter is cumulative, and ES6 is a dynamic reference. If the above reference is changed to CommonJS code, an error is reported because in odd.js, the even.js code is not executed. Change the CommonJS specification load code to:

//even.js
var odd = require('./odd.js');

var counter = 0;
module.exports = function even(n){
    counter ++;
    console.log(counter);

    return n == 0 || odd(n-1);
}
Copy the code
//odd.js
var even = require('./even.js');

module.exports = function odd(n){
    returnn ! = 0 && even(n-1); }Copy the code
//index.js
var even = require('./even.js');

var x = even(5);
console.log(x);

var y = even(5);
console.log(y);
Copy the code

Execute index.js, and the output is as follows:

$ babel-node index.js
1
/Users/name/Projects/node/ES6/odd.1.js:6
    returnn ! = 0 && even(n - 1); ^ TypeError: even is not afunction
    at odd (/Users/name/Projects/node/ES6/odd.1.js:4:22)
Copy the code

3. Summary

1) CommonJS modules are executed on load. Once a module is “looping”, only the parts that have been executed are printed, and the parts that have not been executed are not printed.

2) ES6 module dynamically references exported modules, variables, and objects. When encountering the module loading command import, it does not execute the module, but only generates a reference to the loaded module.

The CommonJS module specification applies primarily to back-end Node.js, which synchronizes module loading, so the module is already executed by the time the module is looped in. It is recommended to use ES6 module specifications in front-end engineering and support the syntax introduced by ES6 module by installing Babel transcoding plug-in.

The page content is mainly from the introduction of Module in GETTING Started with ES6 standards. If the description is not clear or wrong, welcome to comment on it.

References:

ES6 Standard Introduction Module

Node.js Cycle

ES-Module-Loader