Modular front-end - thoroughly get to know AMD, CMD, ESM and CommonJS

We know that before NodeJS, because there is no overly complex development scenarios, the front end is not modular, modular back-end only exist. NodeJS after birth, it uses a modular specification of CommonJS. Since then, js modular began rapid development.

Modular development approach can provide code reuse rate, easy to manage code. Typically, a file is a module, has its own scope, only specific variables and functions exposed outward . Js popular modular specification has CommonJS, AMD, CMD and modular system for ES6. Here we begin introduced one by one:

CommonJS

NodeJS is CommonJS main practitioners specification, it has four important environment variables provide support for modular realization: module, exports, require, global. Actual use, with module.exportsthe definition of the interface module current external output (not recommended for direct use exports), with a requireload module.

// 定义模块math.js
var basicNum = 0;
function add(a, b) {
  return a + b;
}
module.exports = { //在这里写上需要向外暴露的函数、变量
  add: add,
  basicNum: basicNum
}

/** 必须加./路径,不加的话只会去node_modules文件找 **/
// 引用自定义的模块时,参数包含路径,可省略.js
var math = require('./math');
math.add(2, 5);

// 引用核心模块时,不需要带路径
var http = require('http');
http.createService(...).listen(3000);

CommonJS loading module in a synchronous manner. In the service side, the module files are stored in a local disk, read very fast, so this is no problem. But the browser is limited to network reasons, a more reasonable solution is to use asynchronous loading.

exportsAnd module.exportthe difference between:

exports: For itself in terms of a variable (object), it is not a reference module, which is {}a reference that points to module.exportsthe {} block. Use only .the syntax exposure variables outside.

module.exports: moduleIs a variable that points to a memory, exportsis modulean attribute, stored in memory, then exportsattribute points to {}the module. You can use either .syntax, you can also use =direct assignment.

AMD和require.js

AMD specification uses asynchronous load module , the module is loaded it does not affect the operation of the back of the statement. This statement is all dependent modules, are defined in a callback function, wait until after the completion of loading, the callback function will run. Here are implemented with modular require.js AMD specifications: with require.config()reference to the path designation, a definde()definition module, a require()load module.

First, we need to introduce require.js file and a file entry main.js. main.js configure require.config()and provides basic modules used in the project.

/** 网页中引入require.js及main.js **/
<script src="js/require.js" data-main="js/main"></script>

/** main.js 入口文件/主模块 **/
// 首先用config()指定各模块路径和引用名
require.config({
  baseUrl: "js/lib",
  paths: {
    "jquery": "jquery.min",  //实际路径为js/lib/jquery.min.js
    "underscore": "underscore.min",
  }
});
// 执行基本操作
require(["jquery","underscore"],function($,_){
  // some code here
});

Reference module, we will put the module name []as the reqiure()first parameter; if we define the module itself is also dependent on other modules, then they need to be placed []as the define()first parameter.

// 定义math.js模块
define(function () {
    var basicNum = 0;
    var add = function (x, y) {
        return x + y;
    };
    return {
        add: add,
        basicNum :basicNum
    };
});

// 定义一个依赖underscore.js的模块
define(['underscore'],function(_){
  var classify = function(list){
    _.countBy(list,function(num){
      return num > 30 ? 'old' : 'young';
    })
  };
  return {
    classify :classify
  };
})

// 引用模块,将模块放在[]内
require(['jquery', 'math'],function($, math){
  var sum = math.add(10,20);
  $("#sum").html(sum);
});

CMD and sea.js

AMD implementor require.js stated dependent upon the module loaded in the first time and the code in the module to execute:

define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
    // 等于在最前面声明并初始化了要用到的所有模块
    if (false) {
      // 即便没用到某个模块 b,但 b 还是提前执行了。**这就CMD要优化的地方**
      b.foo()
    } 
});

CMD is another js modular approach, it is very similar to AMD, except that: AMD respected dependent on front, executed in advance, CMD respected rely nearby, delayed execution . This specification is actually produced in sea.js promotion process.

/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
     // 等于在最前面声明并初始化了要用到的所有模块
    a.doSomething();
    if (false) {
        // 即便没用到某个模块 b,但 b 还是提前执行了
        b.doSomething()
    } 
});

/** CMD写法 **/
define(function(require, exports, module) {
    var a = require('./a'); //在需要时申明
    a.doSomething();
    if (false) {
        var b = require('./b');
        b.doSomething();
    }
});

/** sea.js **/
// 定义模块 math.js
define(function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        return a+b;
    }
    exports.add = add;
});

// 加载模块
seajs.use(['math.js'], function(math){
    var sum = math.add(1+2);
});

ES6 Module

ES6 on the level of language standards, to achieve the function modules, and achieve quite simple, designed to be versatile browser and server module solutions. Its main function module consists of two commands: exportand import. exportCommand is used to specify the module's external interfaces, importcommand input function provided by other modules.

/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };

/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
    ele.textContent = add(99 + basicNum);
}

As illustrated, using the importcommands, the user needs to know to be loaded variable name or function name. In fact ES6 also provides a export defaultcommand to specify a default output module, the corresponding importstatement does not require the use of braces. It also cited more close to the wording of ADM.

/** export default **/
//定义输出
export default { basicNum, add };

//引入
import math from './math';
function test(ele) {
    ele.textContent = math.add(99 + math.basicNum);
}

ES6 module is not an object, importthe command will be JavaScript engine static analysis, compiled on the introduction of the module code, instead of loading the code runs, it is not possible to load conditions. Precisely because of this, it makes static analysis possible.

ES6 module features:

  • Strict mode: ES6 modules automatically use strict mode
  • importread-only properties: importThe property is read-only, can not be assigned, similar constcharacteristics
  • export/importUpgrade: import/exportmust be in the top module, you can not be in scope; secondly for in the module import/exportwill be raised to the top of the module, which is done at compile phase

Differences ES6 module and module CommonJS

1. CommonJS module output is a copy of a value, ES6 module output is a reference value
  • CommonJS module output is copied values , that is to say, once the output value, changes within a module can not influence this value .
  • Operation mechanism and CommonJS ES6 module is not the same. JS engine when the script for static analysis, experience module loading command import, it will generate a read-only reference. Wait until the script actually executed, and then based on this read-only reference to the module is loaded inside to value. In other words, for ES6 a importbit like the Unix system "symbolic link", the original value has changed, importthe value of variable loading will follow. Thus, for ES6 module is a dynamic reference value and is not cached, its variable bindings inside the module in the module.
2. CommonJS run-time module is loaded, ES6 output interface module is a compile-time
  • When the loading operation: CommonJS is the object module; i.e., when the input module is to load the whole, to produce an object, then the object is read from the method above, this load is called "load running."
  • Loading compile time: ES6 module is not the object, but by exportcode commands explicitly specified output, importwhen in the form of a static command. That importcan be loaded at a specified output value, rather than loading the entire module, this load is called "Load compile time." Internal modules referenced changes, will react to the outside.

CommonJS load of an object (ie module.exportsproperty), the object will be completed only run the script generation. ES6 module rather than an object, it's just a static external interface definitions, the code will be generated in the static resolution phase.

Ado, a direct look at the code:

See example CommonJS first output copy:

// a.js
let a = 1;
let b = { num: 1 }
setTimeout(() => {
    a = 2;
    b = { num: 2 };
}, 200);
module.exports = {
    a,
    b,
};

// main.js
// node main.js
let {a, b} = require('./a');
console.log(a);  // 1
console.log(b);  // { num: 1 }
setTimeout(() => {
    console.log(a);  // 1
    console.log(b);  // { num: 1 }
}, 500);

The so-called output copy, or if you know too NodeJS webpack achieve the CommonJS (do not know can see this article ), you know: exportsthe object is uniquely associated module inside and outside, content CommonJS output, that is exportsthe end of the attributes of the object, the module runs, attribute is determined .

Examples ES6 Module Look output:

// a.mjs
let a = 1;
let b = { num: 1 }
setTimeout(() => {
    a = 2;
    b = { num: 2 };
}, 200);
export {
    a,
    b,
};

// main.mjs
// node --experimental-modules main.mjs
import {a, b} from './a';
console.log(a);  // 1
console.log(b);  // { num: 1 }
setTimeout(() => {
    console.log(a);  // 2
    console.log(b);  // { num: 2 }
}, 500);

Cited above is the difference between the output and ES6 Module CommonJS output value, changes the internal modules referenced, the reaction will be on the outside, which is ES6 Module Specification.

to sum up

  1. AMD / CMD / CommonJs js modular development is the specification, the corresponding implementation is require.js / sea.js / Node.js

  2. CommonJs mainly for the server, AMD / CMD / ES Module aimed browser, confusing is AMD / CMD. (By the way, for the difference between the server and browser for what is the end of it? General server-side synchronous load file, that needs a module, the server will stop and wait for it to load and execute again. Here if there are other back-end languages ​​such as java. the browser side to ensure efficiency, we need asynchronous loading, which requires a pretreatment in advance will require parallel load module file is good.)

  3. AMD / CMD difference, though they are parallel load js files, but still differ, AMD is pre-loaded in the parallel load js files simultaneously, but also parses the implementation of the module (since also need to do so before loading a module this module depends on module need to be loaded); and CMD is lazy loaded, although it will start parallel load js files, but does not perform, but only executed when needed.

  4. AMD / CMD advantages and disadvantages. Another advantage is a disadvantage, can control browsing.
    AMD Advantages: Fast loading, especially encounter multiple large files, because the parallel resolution, so you can parse multiple files at the same time.
    AMD drawback: the parallel load, asynchronous processing, the loading sequence is not necessarily, it may cause some confusion, even for a program buried pit.

    CMD advantages: Because the resolution is carried out only if the js file when in use, therefore, the order of execution of each of the JS file are reflected in the code, is controllable.

    CMD Disadvantages: execution waiting time will be superimposed. Because each file execution is executed synchronously (serial execution), so the time is all file parsing and execution of time, especially in the more large files, this disadvantage is particularly evident. (PS: re-reading this article, found here writing is not very accurate and precise terms, JS is single-threaded, all the JS file execution time superimposed AMD and CMD CMD is the same as it is to perform when used, can not. use of free time, but AMD is a file loaded on the implementation of good, can often take advantage of some free time. so, the merits CMD than AMD is still very obvious, after all, AMD is not necessarily a good time to load the JS engine idle time!)

  5. CommonJS difference and ES Module: CommonJS module output is a copy of a value, ES6 module output is a reference value

  6. how to use? CommonJs words, because NodeJS is its implementation, so use node on the line, they do not introduce other packages. AMD is through <script>label introduced require.js, CMD is introduced sea.js

Guess you like

Origin www.cnblogs.com/chenwenhao/p/12153332.html