The JavaScript module article describes how to organize your code for modularity. Modularity can hide private properties and methods, exposing only public interfaces. So others don't have to build the wheel from scratch, just use the functionality defined in your module. The namespace is guaranteed and there is no naming conflict.
But without a set of specifications to do the reference, everyone with their own preferences to define the module, the use of other people's module will appear obstacles. This article introduces the specification of the Universal Definition JS module: COMMONJS and AMD
CommonJS
The Nodejs module system uses COMMONJS mode. COMMONJS Standard stipulates that a separate file is a module, the module will need to expose the variables into the exports object, can be arbitrary objects, functions, arrays, etc., are not placed in the exports object is private. The module is loaded with the Require method, which reads the module file to obtain the exports object.
For example, define a hi.js:
var str = ‘Hi‘;function sayHi(name) { console.log(str + ‘, ‘ + name + ‘!‘);}module.exports = sayHi;
Define the Sayhi function in the Hi module and expose it with exports. The non-exposed variable str cannot be accessed externally. For other modules to use this function, you need to require this Hi module first:
var Hi = require(‘./hi‘);Hi(‘Jack‘); // Hi, Jack!
The variable hi in the first line is actually module.exports = sayHi;
the Sayhi function of the output in the hi.js.
Note that the above require loaded with a relative path, let Nodejs go to the specified path to load the module. If the relative path is omitted, the default is to find the Hi module under the Node_modules folder, which is likely to be error-able because it cannot be found. If you are loading a node built-in module, or NPM downloading the installed module, you can omit the relative path, for example:
var net = require(‘net‘);var http = require(‘http‘);
In the JavaScript module article introduced the JS module of the wording, where the module,exports,require is the new JS syntax? Not the new syntax, just the COMMONJS syntax sugar. Node compiles the above hi.js into:
// 准备module对象:var module = { id: ‘hi‘, exports: {}};var load = function (module) { function sayHi(name) { console.log(‘Hi, ‘ + name + ‘!‘); } module.exports = sayHi; return module.exports;};var exported = load(module);// 保存module:save(module, exported);
First define a Module object, the property ID is the module name is the file name, attribute exports is the object that will eventually need to be exposed. Therefore we in the Hi.js code obviously does not have the Var declares the module object, but module.exports = Sayhi, actually does not have the error. The reason is that the module is that node is ready for us before loading the JS file. Finally, node saves the module object with a custom function save.
When node saves all the module objects, when we get the module with require (), node finds the corresponding module based on Module.id and returns the module. Exports, so that the output of the module is realized.
Commonjs is synchronous, meaning that you want to invoke the method in the module, you must first load the module with require. This is not a problem for server-side Nodejs, because the module's JS files are on the local hard disk, the CPU read time is very fast, synchronization is not a problem.
But in the client browser with COMMONJS load module will depend on the speed, if the use of synchronization, network sentiment is unstable, the page may be stuck. The AMD Async module definition is therefore present for the client.
Amd
AMD (asynchronous module Definition) asynchronously loads the module. The AMD standard stipulates that the module is defined with define, and the module is loaded with require:
define(id, [depends], factory); require([module], callback);
First look at the example of the Define definition module:
define([‘module1‘, ‘module2‘], function (module1, module2) { …… return { … };});
The first parameter ID is your module name, which is omitted from the previous example. In fact, this ID is useless, it is for developers to see.
The second parameter [depends] is the other module on which the module relies, and in the above example the module relies on another two modules Module1 and Module2. If you define a module that does not depend on any other module, the parameter can be omitted.
The third parameter, factory, produces (that is, return) an object for external use (I see some of the data in the name of the parameter named callback, the sense callback semantics is a bit ambiguous, named factory more appropriate).
After defining the module, look at the example of loading the module with require:
require([‘yourModule1‘, ‘yourModule2‘], function (yourModule1, yourModule2) { ……});
Compared with Commonjs's require method, AMD's require has one more parameter callback.
The first parameter is the module name that needs to be loaded, which can be an array, meaning that multiple modules are loaded. When loading a module, if the module has a [depends] parameter in its define, the dependent module specified in [depends] is loaded first. After loading the dependent module in [depends], run the factory method in the define to get an instance of the module. The instance is then passed in the second parameter callback as a parameter.
The second parameter callback the callback function, which is the instance object that is obtained after the module is loaded according to the first parameter. When the module specified by the first parameter is all loaded, the callback is executed.
The Require loading process is divided into several steps:
The first step is to convert the module name of the dependent list to a URL, which is commonly known as BasePath + ModuleID + ". js". For example:
require(["aaa", "bbb"], function(a, b){});//将在require内部被转换成://require(["http://1.2.3.4/aaa.js", // "http://1.2.3.4/bbb.js"], function(a, b){});
The second step is to see if the module has been loaded (the state is 2) or is being loaded (the state is 1) from the array of detected objects. Only the node has never been loaded before it enters the loading process.
In the third step, the state of the module is set to 1, indicating that it is being loaded. Create a script tag, add the URL of the module to SRC, and bind the Onload,onreadystatechange,onerror event to start loading the script into the DOM tree. When the browser loads, it triggers the binding on event, which changes the module's state to 2, indicating that it has been loaded.
The fourth step, the module URL, dependency list, state and so on to build a detection object array, for the second step detection.
You can put all the code that needs to use the variables and methods in the module into the callback. Require the following code will continue to execute, so that the browser can avoid the situation of suspended animation.
Implementation of the AMD Specification JS Library has: Require.js. Take a look at a require.js example:
//myModule1.jsdefine(function() { var m1 = {}; m1.say = function() { console.log(‘Hi myModule1!‘); } return m1;});//myModule2.jsdefine([‘myModule3‘], function(m3) { var m2 = {}; m2.say = function() { m3.say(); console.log(‘Hi myModule2!‘); } return m2;});//myModule3.jsdefine(function() { var m3 = {}; m3.say = function() { console.log(‘Hi myModule3!‘); } return m3;});//HTMLconsole.log("before require");require([‘myModule1‘,‘myModule2‘], function(m1, m2){ m1.say(); m2.say();});console.log("after require");//before require//after require//Hi myModule1!//Hi myModule3!//Hi myModule2!
The HTML is executed first console.log(“before require”);
, and the first one is printed.
Then execute require, because Require.js is an AMD asynchronous load, so execute the require after the console.log(“after require”);
statement, printing out the second one.
Execute require to load the module sequentially. Load MyModule1 first. There are no [depends] parameters found in the define of MyModule1, and no other modules are dependent. So run the factory method in define to get MyModule1 instance object M1.
Load the MyModule2 again. MyModule2 is found to be dependent on myModule3, so the MyModule3 is loaded. The myModule3 has no [depends] parameters and does not depend on other modules. So run factory to get myModule3 instance object m3.
After MyModule3 is loaded, the factory running MyModule2 gets myModule2 instance object m2.
After the myModule2 is loaded, all modules of the require are loaded and run the callback function. The previously obtained instance objects M1 and M2 are passed as arguments to the callback function.
Run m1.say();
print out the third article
Run m2.say();
, according to the method definition, first run m3.say();
print out fourth, then run console.log(‘Hi myModule2!’);
print out fifth.
Some libraries are not strictly in accordance with AMD, using the Define () function to define the module, at this time need to use shim technology (so-called Shim is the gasket, that is, a new API into an old environment, and only by the old environment in the existing means to achieve). For example Require.js defines the shim attribute for Require.config, which we use to load the two libraries that do not use the AMD specification underscore and backbone:
require.config({ shim: { ‘underscore‘:{ exports: ‘_‘ }, ‘backbone‘: { deps: [‘underscore‘, ‘jquery‘], exports: ‘Backbone‘ } }});
Of course, this is not the introduction of require.js, more require.js usage, please refer to the official website
Summarize
Whether it is the server-side COMMONJS specification that is used by Nodejs or the AMD specification of the client, we can standardize our custom modules to make them easier for others to use.
Zhang Xinlin
Links: http://www.jianshu.com/p/fc858878d891
Source: Pinterest
Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please specify the source.
Commonjs and AMD