Module specification of COMMONJS
The relationship between node and browser, as well as the organization of the COMMONJS, the ECMAScript
Node uses COMMONJS's modules specification to realize a set of modular system, so first look at the COMMONJS module specification.
Commonjs The module definition is very simple, mainly divided into module reference, module definition and module identification 3 parts.
1. Module reference
The sample code referenced by the module is as follows:
var math = require (' math ');
In the COMMONJS specification, there is a require () method that accepts the module identifier to introduce a module's API into the current context.
2. Module definition
In a module, the context provides a require () method to introduce an external module. In response to the introduced functionality, the context provides the method or variable that the exports object uses to export the current module, and it is the only exported export. In a module there is also a Module object, which represents the module itself, and exports is the property of modules. In node, a file is a module, and the method is mounted on the exports object as a property to define how it is exported:
Math.js
exports.add = function () {
var sum = 0, i = 0, args = arguments, l = args.length;
while (I < l) { sum = args[i++];}
return sum;
};
In another file, when we introduce a module through the Require () method, we can invoke the defined property or method:
Program.js
var math = require (' math ');
Exports.increment = function (val) {return Math.add (Val, 1);
3. Module identification
The module ID is actually a parameter passed to the Require () method, which must be a string that matches the name of the small hump, or. 、.. The relative path to the beginning, or the absolute path. It can have no filename suffix. js. The definition of the module is very simple and the interface is very concise. Its significance is to limit classified collection methods and variables to private scopes, while supporting the introduction and export functions to seamlessly connect upstream and downstream dependencies. Each module has a separate space, they do not interfere with each other, in the reference also appears neat.
The module realization of node
node in the implementation is not completely in accordance with the specification, but the module is a certain choice of specifications, but also added a little of their own needs characteristics. Although exports, require, and module in the specification sound simple, the process needs to be known about what node is going through in the process of implementing them.
The introduction of modules into node requires 3 steps to follow.
1. Path analysis
2. Document positioning
3. Compile and Execute
In node, the module is divided into two types: one is the module provided by node, called the Core module, the other is a user-written module called a file module .
• The core module is compiled into the binary execution file during the compilation of the node source code. When the node process is started, some core modules are loaded into the memory directly, so when this part of the core module is introduced, the two steps of locating and compiling the files can be omitted, and the priority is given in the path analysis, so the load speed is the fastest.
• File modules are dynamically loaded at runtime, requiring complete path analysis, file positioning, compilation execution, and slower speed than core modules.
1. Priority from cache loading
As with front-end browsers that cache static script files to improve performance, node is caching the introduced modules to reduce the overhead of two of introductions. The difference is that browsers simply cache files, and node caches objects that are compiled and executed. Whether the core module or the file module, the Require () method for the same module of the two load is always the caching priority, which is the first priority. The difference is that the cache check of the core module is preceded by the cache check of the file module.
2. Path analysis and file positioning
Because there are several forms of identifiers, there are varying degrees of difference in the search and positioning of modules for different identifiers.
1). module identifier Analysis
Node is a module lookup based on a module identifier. module identifiers are mainly grouped into the following categories in node.
Core modules, such as HTTP, FS, path, and so on.
. Or.. The starting relative path file module.
Absolute path file module with/start.
A non-path file module, such as a custom connect module.
• Core Modules
The priority of the core module is second only to cache loading, which has been compiled into binary code during node source code compilation, with the fastest loading process. If you attempt to load a custom module that is the same as the core module identifier, it will not succeed. If you write an HTTP user module and want to load successfully, you must select a different identifier or a way to swap the path.
• File modules in the form of paths
To... and/or starting identifiers, which are all processed as file modules. When parsing the path module, the Require () method converts the path to the real path and, with the real path as the index, stores the results of the compiled execution in the cache so that the two load times are faster. Because the file module gives node the exact location of the file, it can save a lot of time in the lookup process and its loading speed is slower than the core module.
• Custom Modules
The custom module refers to a Non-core module and is not a path-type identifier. It is a special kind of file module, which may be a file or package form. This type of module lookup is the most time-consuming and the slowest in all ways.
2). File positioning
From the optimization strategy of cache loading, the process of path analysis, file location and compile execution is not needed in two times, which greatly improves the efficiency of loading modules again. However, in the location of the file, there are some details to note, which mainly includes the file extension analysis, directory and package processing.
• File name extension analysis
The COMMONJS module specification also allows the file name extension to be included in the identifier, in which case node complements the extension in the order of. JS,. JSON,. node, and then tries. In the process of trying, you need to call the FS module to determine whether the file exists synchronously. Because node is single-threaded, this is where it can cause performance problems. The trick is: if it's a. node and. json file, it will speed up a little faster with an extension on the identifier passed to require ().
• Catalog Analysis and Packages
During the parsing of identifiers, require () after parsing the file name extension, may not have found the corresponding file, but has a directory, where node will treat the directory as a package.
In this process, node supports the COMMONJS package specification to a certain extent. First, node locates Package.json (the package description file defined by the COMMONJS Package specification) in the current directory, resolves the package description object by Json.parse (), and takes out the filename specified by the main property to locate it. If the file name is missing an extension, the step of the extension parsing is entered. If the main property specifies a file name that is wrong, or if there is no Package.json file at all, node will use index as the default filename, and then look for Index.js, Index.node, and Index.json.
If no files are positioned successfully during catalog parsing, the custom module goes to the next module path for lookups. If the module path array is traversed and the destination file is still not found, the exception that the lookup failed is thrown.
3). Module compilation
In node, each file module is an object, which is defined as follows:
function Module (ID, parent) {
this.id = ID;
This.exports = {};
This.parent = parent;
if (parent && parent.children) {
Parent.children.push (this);
}
This.filename = null;
this.loaded = false;
This.children = [];
}
Compilation and execution are the last stages of introducing a file module. When you navigate to a specific file, node creates a new module object and then loads and compiles it according to the path. For different file extensions, the Load method is also different, as shown in the following example.
.js files.
Compile execution after reading the file synchronously through the FS module.
.node files.
This is an extension file written in C/s + +, and the last compiled file is loaded through the Dlopen () method.
.json files.
After the file is read synchronously through the FS module, the result is returned with Json.parse ().
• The rest of the extension files.
They are loaded as. js files.
Each successfully compiled module caches its file path as an index on the Module._cache object to improve the performance of the two-time introduction.
Compilation of JavaScript modules
Back to the COMMONJS module specification, we know that there are 3 variables in each module file, require, exports, module, but they are not defined in the module file, so where does it come from? Even in the node's API documentation, we know that there are two variables in each module, __filename, __dirname, and where do they come from? If we put the process of directly defining the module on the browser side, we will have the situation of polluting the global variable.
In fact, in the process of compiling, node wraps the contents of the JavaScript file acquired. Added in header (function (exports, require, module, __filename, __dirname) {\ n, added \ n} at tail);. A normal JavaScript file will be packaged as follows:
(function (exports, require, module, __filename, __dirname) {
var math = require (' math ');
Exports.area = function (RADIUS) {return
Math.PI * radius * RADIUS;
};
});
This allows for scope isolation between each module file. The code after the wrapper is executed via the Runinthiscontext () method of the VM native module (like Eval, just with a clear context, not polluting the global), and returns a specific function object. Finally, the exports property of the current module object, the Require () method, module (the module object itself), and the complete file path and file directory obtained in the file positioning are passed as parameters to this function () execution.
3. Package and NPM
Outside the module, packages and NPM are a mechanism for linking modules.
The COMMONJS package specification is also very simple, consisting of two parts of the package structure and the package description file, which is used to organize the various files in the package, and the latter is used to describe the package information for external read analysis.
1. Package Structure
A package is actually an archive file, a directory that is packaged directly into a. zip or tar.gz format, and is restored as a directory after installation. Package catalogs that fully conform to the COMMONJS specification should contain these files.
Package.json: Package description file.
Bin: The directory where executable binaries are stored.
LIB: A directory used to store JavaScript code.
Doc: The directory where documents are stored.
Test: The code that holds the unit test case.
2. Package description File
The package description file is used to express non code-related information, which is a JSON-formatted file--package.json, located in the root directory of the package, is an important part of the package. All of NPM's behavior is closely related to the field of the package description file.
This can be seen at NPM's official website on the definition of Package.json specifications.
Through NPM AddUser, NPM Publish can upload its package to the NPM warehouse.
Third, the digression: AMD, CMD, compatible with a variety of module specifications Class Library
1. AMD
is an extension of the COMMONJS module specification, and its modules are defined as follows:
Define (ID, dependencies, Factory);
2.CMD
3. Compatible
In order to allow the same module to run on the front and back, in the process of writing needs to consider the compatibility of front-end and the implementation of the module specification environment. To maintain the consistency of the front and back ends, the class library developer needs to wrap the class library code in a closure. The following code demonstrates how to define the Hello () method in a different running environment that is compatible with node, AMD, cmd, and common browser environments:
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.