AMD, CMD, CommonJS, ES6
A, AMD
AMD, Asynchronous Module Definition It is a specification for modular development on the browser side. It is not javascript native support, so using THE AMD specification for page development needs to use the corresponding library, namely RequireJS. AMD is actually the output of the scope of module definition of RequireJS in the process of popularization.
RequireJS addresses two main issues:
- multiple
js
When a file has dependencies, the dependent file must be loaded into the browser before the dependent file js
The browser blocks the render thread when loading, and the more files loaded, the longer the page is unresponsive
Usage: require requires a root to start the search dependency (like main in package.json), and data-main to specify the root.
<script src="script/require.js" data-main="script/app.js"></script>
Copy the code
This specifies that root is app.js, and only modules that are directly or indirectly dependent on app.js will be inserted into the HTML.
define()
Function: The function used to define a module.args0
: an array of module names to import,arg1
: after the dependency is introducedcallback
.callback
The argument of phi is the thing introduced. If there are multiple dependencies, the parameters are passed in the order they were introduced.
define(['dependence_name'], (args) => {
// Args is a dependence_name
// ... Your fucking code ...
return your_export;
});
Copy the code
require()
Function: A function used to introduce a module.
require(['import_module_name'], (args) => {
// args is what is imported from import_module_name
// ... Your fucking code ...
});
Copy the code
require.config
Configuration:baseUrl
Loading:module
The root of the pathpaths
: used to map the module path below the root path that does not existshimes
: to load theAMD
Specification of thejs
Second, the CMD
CMD, Common Module Definition, Common Module Definition CMD was created during the promotion of sea-.js. In the CMD specification, a module is a file.
define(function(require, exprots, module) {
const fs = require('fs'); // Accept the module id as the only argument
// exports, Module is similar to CommonJS
exports.module = {
props: 'value'
};
});
seajs.use(['test.js'].function(test_exports) {
/ /...
});
Copy the code
null | AMD | CMD |
---|---|---|
How dependencies are handled when defining modules | Dependency prefixes are preferred, which declare dependent modules at the time of definition | Advocate proximity, requiring only when the module is used |
Loading way | async | async |
The way module is executed | After the module is loaded, the module will be executed. After the module is loaded, all modules will enter the require callback function to execute the main logic. Dependencies may not be executed in the same order as they are written, but the main logic must be executed after all dependencies have been loaded (similar to promise.all). | Once a dependency is loaded, it is not executed; it is just downloaded. The module is executed only when the require statement is encountered after all modules are loaded. Modules are executed in exactly the same order as they are written. |
Third, CommonJS
The OFFICIAL W3C apis can only be Browser based, and CommonJS makes up for the lack of javascript.
NodeJS is the primary practitioner of the CommonJS specification. It has four important environment variables that support modular implementations: Module, exports, require, and Global. In practice, use module.exports(not recommended) to define the API for exports and use require to reference modules. CommonJS loads modules synchronously. On Server the module files are on the local disk, so it’s ok to load them very quickly, but in Browser it makes more sense to load them asynchronously for network reasons. CommonJS module definition is divided into three parts: module reference, module definition and module identification.
1. Module Reference:
const fs = require('fs');
Copy the code
Require’s execution steps:
- If it is a core module, such as FS, return directly to the module
- If it is a path, concatenate it into an absolute path, and read the cache require.cache before reading the file. (If there is no extension, then
js => json => node
(read as a binary plug-in module) - The module after first loading will be in
require.cache
, so require multiple times, resulting in the same object (reference to the same object) - When executing module code, the module is wrapped in the following mode so that it is scoped within the module.
(function (exports, require, module, __filename, __dirname) {
// module codes
});
Copy the code
- The wrapped code is executed with the VM native module’s runInThisContext() method (similar to eval, but with explicit context that does not pollute the environment) and returns a function object. Finally, the current module object
exports
,require
Methods,module
And from the location of the fileFull file path
(including file name) andFile directory
Pass to this function execution.
2. Module Definition:
function fn() {}
exports.propName = fn;
module.exports = fn;
Copy the code
A Module object represents the module itself, and exports is a module property. Exports can be defined by mounting properties on exports, or by assigning values directly to module.exports (recommended).
3. Module Identification:
The module identifier is the argument passed to the require() method, which can be a relative or absolute path, or a string that conforms to the small camel name. NodeJS CommonJS implementation: Node module is divided into the core module provided by Node and user prepared file module.
Core modules are compiled into binary executables during compilation of Node source code. Some core modules are loaded into memory when Node is started, so when referencing core modules, file location and compilation execution steps can be omitted, and the path judgment is prioritized, so it is the fastest to load. The file module is dynamically loaded at runtime, which requires complete path analysis, file location, compilation and execution, and is slower than the core module. There are three steps to importing a module into NodeJS:
-
Paths = [‘ node_modules in current directory ‘, ‘node_modules in parent directory’,… ‘Node_modules in parent directory’]
-
File location: file extension analysis, directory and package processing.
- File extension analysis:
Node
Will follow the.js => .json => .node
The order of complementing extensions is tried in sequence. (In the process of trying to call the synchronous FS module to see if the file exists) - Directory and package handling: there may be no corresponding files, but corresponding directories exist. At this moment
Node
Will look in this directorypackage.json
And,JSON.parse
Out of themain
(Entry file) corresponding file. ifmain
Attribute error or nonepackage.json
, it willindex
As amain
. If no file is successfully located, go to the next module path and repeat the above work, if the entiremodule.paths
If the target file is not found after traversing, the search failure error is run.
- File extension analysis:
-
Compile execution: Each module file is an object in Node, and compile execution is the last stage of importing file modules. Once the file is located, Node creates a new module object, which it loads and compiles according to the path. Different file extensions are loaded differently:
.js
Through:fs
The module synchronously reads the file and compiles it.node
: this isC++
Prepared by extension file, throughdlopen()
Load the file generated by the last compilation..json
With:.js
File, for laterJSON.parse
Parsing returns the result. Other files: all pressjs
In the way of analysis.
null | CommonJS | ES6 |
---|---|---|
keywords | exports, require, module, __filename. __dirname | import, export |
The import | const path = require(‘fs’); All attributes exported by a module must be imported | import path from ‘path’; You can just introduce one |
export | module.exports = App; | export default App; |
Imported objects | Arbitrarily modify the value of the copy | Reference of a value cannot be modified arbitrarily |
The import number | Require can be required any number of times, except for the first time, and subsequent require can be taken from require.cache | Import in the header only once |
loading | Run time loading | Compile-time output interface |
ES6 module
ES6 module has been relatively familiar, usage is not repeated, directly on the code:
import { prop } from 'app'; // Import prop from app
import { prop as newProp } from 'app'; // Perform the same function as above, but rename the imported prop to newProp
import App from 'App'; // Import App default
import * as App from 'App'; // Import all properties of the App into the App object
export const variable = 'value'; // Export a constant named variable
export {variable as newVar}; // Export variable as newVar, similar to the import renaming
export default variable = 'value'; // Export variable as default
export {variable as default}; // The same as above
export {variable} from 'module'; // Export variable from module, which cannot be accessed
export {variable as newVar} from 'module'; // The following is not clear
export {variable as newVar} from 'module';
export * from 'module';
Copy the code
Ps: the ES6 module imports variables (which should be more accurately called constants) with the following characteristics: the variables are promoted, as if wrapped in object.freeze (), and import/export can only be in the top-level scope
“
ES6 modules differ from CommonJS runtime loading in that import commands are statically parsed by the JavaScript engine and executed prior to the rest of the module (similar to function declarations prior to other statements), meaning that import imports are brought to the top of the file anywhere in the file.
ES6 modules automatically turn on strict mode, even if ‘use strict’ is not written; . When you run a module with an import declaration, the imported modules are first imported and loaded, and the contents of each module are then traversed depth-first based on dependencies. Skip modules that have already been executed to avoid dependency loops.
The standard says very little about what import does, and ES6 leaves the loading details of modules entirely up to the implementation. Generally speaking, when the JS engine runs a module, its behavior can be roughly summarized as the following four steps:
- Parsing: Engine parses module code, checks syntax, and so on.
- Load: Load all introduced modules recursively, depth first.
- Linking: Create a scope for each newly loaded module and bind declarations from the module (including those imported from other modules) into it. when
js
When the engine starts executing the code loaded in the module,import
The processing is over, sojs
The engine executes to a lineimport
We’re not gonna do anything about it. Imports are implemented statically, and by the time the code is executed, nothing is done.
Speaking of modules, let me mention the difference between modules and scripts (note that I’m only talking about the difference in Web browsers) :
“
– | module | script |
---|---|---|
Usage (there are other implementations, too, which are not discussed here) | <script src=”./source.js type=”module” /> | <script src=”./source.js type=”text/javascript” /> |
download | ① When <script> is encountered, defer is automatically applied. ② Download && parsing Module. ③ Recursively download the resources imported from module. The download phase is complete. |
When <script> is encountered, document rendering is blocked by default and download is enabled. |
Implement way | ① After downloading, the resources imported in module will be recursively executed. ② Then execute the Module itself. Ps: The inline Module is missing the steps to download the Module itself. The other steps are the same as the imported Module. |
The default is to execute immediately after downloading |
Reference links:
Front-end modular: CommonJS,AMD,CMD,ES6
ES6 module system
NodeJS