Read node. js together (3) ---- module (Modules)

Source: Internet
Author: User
Tags emit

Module)

Stability: 5-locked

Node has a simple module loading mechanism. The files and modules in node correspond one to one. For example, foo. js loads the circle. js module in the same folder.

Foo. js content:

[Javascript]
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> var circle = require ('./circle. js ');
Console. log ('the area of a circle of radius 4 is'
+ Circle. area (4); </SPAN>

Var circle = require ('./circle. js ');
Console. log ('the area of a circle of radius 4 is'
+ Circle. area (4); circle. js content: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> var PI = Math. PI;
 
Exports. area = function (r ){
Return PI * r;
};
 
Exports. circumference = function (r ){
Return 2 * PI * r;
}; </SPAN>

Var PI = Math. PI;

Exports. area = function (r ){
Return PI * r;
};

Exports. circumference = function (r ){
Return 2 * PI * r;
}; The circle. js module exports the area () method and the circumference () method. To export an object, you need to add the specified exports object.

The module variables are private. In this example, the variable PI is private to circle. js.

The module mechanism is implemented in the require ('module') module.

 


Cycles)

 


When a ring-shaped require () call exists, when a module is returned and executed, loading may not be completed. Consider the following scenario:
A. js:
[Javascript]
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> console. log ('a starting ');
Exports. done = false;
Var B = require ('./B. js ');
Console. log ('in a, B. done = % J', B. done );
Exports. done = true;
Console. log ('a done'); </SPAN>

Console. log ('a starting ');
Exports. done = false;
Var B = require ('./B. js ');
Console. log ('in a, B. done = % J', B. done );
Exports. done = true;
Console. log ('a done'); B. js: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> console. log ('B starting ');
Exports. done = false;
Var a = require ('./a. js ');
Console. log ('in B, a. done = % J', a. done );
Exports. done = true;
Console. log ('B done'); </SPAN>

Console. log ('B starting ');
Exports. done = false;
Var a = require ('./a. js ');
Console. log ('in B, a. done = % J', a. done );
Exports. done = true;
Console. log ('B done'); main. js: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> console. log ('main starting ');
Var a = require ('./a. js ');
Var B = require ('./B. js ');
Console. log ('in main, a. done = % j, B. done = % J', a. done, B. done); </SPAN>

Console. log ('main starting ');
Var a = require ('./a. js ');
Var B = require ('./B. js ');
Console. log ('in main,. done = % j, B. done = % j ',. done, B. done); When main. js load. in js,. js needs to load B in sequence. js. at this time, B. js tries to load. js. to prevent an infinite loop, an unfinished. the exports export object of the js copy is returned to B. js module. then B. js completes loading, and its exports export object is provided to. js module.


When main. js loads these two modules, they have all loaded them. The output of this program should be like this: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> $ node main. js
Main starting
A starting
B starting
In B, a. done = false
B done
In a, B. done = true
A done
In main, a. done = true, B. done = true </SPAN>

$ Node main. js
Main starting
A starting
B starting
In B, a. done = false
B done
In a, B. done = true
A done
In main,. done = true, B. done = true if your program has a circular module dependency, make sure that the corresponding plan is made (meaning that it is called when all the dependent modules are loaded, avoid unexpected results caused by calls when the module is not loaded ).


(Loop loading, the require () method has a corresponding mechanism. In the above example, B. when js returns, B. js-loaded. js is not loaded, but when B. when js loads,. js is loaded. At this time, B. a. js will also be updated to complete the object. In fact, I think it may be similar to. js references .)
Core modules)


Some modules in node are compiled into binary. These modules are described in more detail elsewhere in the document.


The core module is defined under the lib folder in the node source code.


If the identifier of the core module is passed in the require () method, it is always preferentially loaded. for example, require ('http') always returns the built-in http module, even if there is a module folder with the same name.


File module Loading Mechanism)


If the correct file name is not found, node will try to load files with extensions such as. js,. json, And. node.
. The js file is interpreted as a javascript text file ,. the json file is converted into a json text file .. the node file is used as a compiled plug-in module and loaded with dloopen. (In the dlopen () function, open the specified dynamic connection library file in the specified mode, and return a handle to the calling process. Use dlclose () to uninstall the opened library .)


When the prefix of a module is "/", it indicates the absolute path of a module File. example: require ('/home/marco/foo. '/home/marco/foo. js 'is loaded as a path.


When the prefix of a module is ". /"indicates the relative path of a module File to call require (). for example, to make foo. require ('. /circle. js') can be found, circle. js and foo. js is in the same directory.


If "./" or "/" is not specified as the file prefix, this module is not a core module, but a module that needs to be loaded from the node_modules folder.


If the given loading path does not exist, the requier () method will throw an Error object and the Error code attribute will be set to 'module _ NOT_FOUND '.

Load the module from the node_modules folder (loading from node_mudoles folders)


If the module identifier passed in to the require () method is not a local module and is not "/",".. /", or ". /", node will append/node_modules to the parent directory path of the current module, and try to load the module in this path.


If it is not found, the node will continue to move to the parent directory of the last layer, and so on... until it reaches the root directory.


For example, if you call require ('bar. js') in the '/home/ry/project/foo. js' file, the node searches for the paths listed below, which are:
/Home/ry/projects/node_modules/bar. js
/Home/ry/node_modules/bar. js
/Home/node_modules/bar. js
/Node_modules/bar. js
This will allow the program to localize their dependencies so that there is no conflict.


Folder is the module (Floder as modules)


It is convenient to put the Organization Program and class library in the directory they contain. Then, a separate entry is provided to specify this class library. There are three methods to pass a folder as a parameter to the require () method.


The first method is to create a package. json file in the root directory and specify a main module. The example of a paceage. json file looks like this:

[Javascript]
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> {"name": "some-library ",
"Main": "./lib/some-library.js"} </SPAN>

{"Name": "some-library ",
"Main ":". /lib/some-library.js "} if the current program path is in. /some-library directory, then require ('. /some-library ') will try to load the path. /some-library/lib/some-library.js.


This is the result that node automatically expands from the package. json file.


If no package exists in this directory. json file, node will try to load an index in this directory. js or index. node file. for example, if no package exists in the preceding example. json file, then require ('. /sone-library ') will try to load: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">./some-library/index. js
./Some-library/index. node </SPAN>

./Some-library/index. js
./Some-library/index. node cache (Caching)

After the module is loaded for the first time, it is cached. This means that calling require ('foo') elsewhere will get the same object and return it, if they scan the same file.


Multiple calls to require ('foo') will not cause the module code to be executed multiple times. this is an important feature. with it, some loaded objects can be returned, and then the dependent objects in the transition period can be loaded, even when they cause ring loading.
(The above section is actually a description of the ring loading introduced in this article, that is, when the require () method in node loads an object, it may be returned before loading is complete, but an index is returned. In a node application, when a module is loaded using require (), it will be searched in the cache first, if yes, it is returned and not loaded .)

If you want the code of a module to be executed multiple times, you can export a method and call this method.

Cache Module Caching caveats)

The module is cached Based on the name of the file they have been parsed, because the current path of the module that calls the require () method is different, resulting in parsing different file names, (load from the node_modules folder). If different files are parsed, The require ('foo') will always return consistent objects.
Module Object)

In each module, the free variable module is a reference that represents the current module. therefore, module. the exports and exports objects are the same. the module is actually not a global variable, but is built into every module.
Module. exports

The exports object is created by the module mechanism. Sometimes, in many cases, you need to make the module an instance of some classes and make exports inaccessible. in order to allocate the objects to moduel. exports object. In this example, we suppose we need to write. js module. [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> var EventEmitter = require ('events'). EventEmitter;
 
Module. exports = new EventEmitter ();
 
// Do some work, and after some time emit
// The 'ready' event from the module itself.
SetTimeout (function (){
Module. exports. emit ('ready ');
},1000); </SPAN>

Var EventEmitter = require ('events'). EventEmitter;

Module. exports = new EventEmitter ();

// Do some work, and after some time emit
// The 'ready' event from the module itself.
SetTimeout (function (){
Module. exports. emit ('ready ');
}, 1000); in another file, we need to do: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> var a = require ('./');
A. on ('ready', function (){
Console. log ('module a is ready ');
}); </SPAN>

Var a = require ('./');
A. on ('ready', function (){
Console. log ('module a is ready ');
}); Note: this operation to allocate objects to the module. exports object must be executed immediately. It will not take effect if it is placed in any callback function.


X. js [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> setTimeout (function (){
Module. exports = {a: "hello "};
}, 0); </SPAN>

SetTimeout (function (){
Module. exports = {a: "hello "};
}, 0); y. js [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> var x = require ('./X ');
Console. log (x. a); </SPAN>

Var x = require ('./X ');
Console. log (x. );

Reprinted please indicate the source: http://blog.csdn.net/qq413041153/article/details/7922126
Module. require (id)
Id String
Return: the object exported from the parsed module.
The module. require () method provides a way to load a module that has been loaded before.
Note: To achieve this, you must obtain an index for this module. Since the require () method returns the exports object, this module is only valid in this specified code, to use it, you need to export it explicitly.
Module. id
String
The identifier of the module. It is a complete path that can represent the module.
Module. filename
String
A complete path that represents the module
Module. loaded
Boolean
Indicates whether the module is loaded or is being loaded.
Module. parent
Module object
Indicates the module that loads the current module.
Module. children
Array
Indicates the sub-modules loaded by the current module.
Conclusion (All together ...)
To obtain accurate file names when you call require (), use the require. resolve () method.
The above code is put together. below is the pseudocode of the advanced algorithm of the require. resolve () method: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> require (X) from module at path Y
1. If X is a core module,
A. return the core module
B. STOP
2. If X begins with './' or '../'
A. LOAD_AS_FILE (Y + X)
B. LOAD_AS_DIRECTORY (Y + X)
3. LOAD_NODE_MODULES (X, dirname (Y ))
4. THROW "not found"
 
LOAD_AS_FILE (X)
1. If X is a file, load X as JavaScript text. STOP
2. If X. js is a file, load X. js as JavaScript text. STOP
3. If X. node is a file, load X. node as binary addon. STOP
 
LOAD_AS_DIRECTORY (X)
1. If X/package. json is a file,
A. Parse X/package. json, and look for "main" field.
B. let M = X + (json main field)
C. LOAD_AS_FILE (M)
2. If X/index. js is a file, load X/index. js as JavaScript text. STOP
3. If X/index. node is a file, load X/index. node as binary addon. STOP
 
LOAD_NODE_MODULES (X, START)
1. let DIRS = NODE_MODULES_PATHS (START)
2. for each DIR in DIRS:
A. LOAD_AS_FILE (DIR/X)
B. LOAD_AS_DIRECTORY (DIR/X)
 
NODE_MODULES_PATHS (START)
1. let PARTS = path split (START)
2. let ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS-1
4. let DIRS = []
5. while I> ROOT,
A. if PARTS [I] = "node_modules" CONTINUE
C. DIR = path join (PARTS [0 .. I] + "node_modules ")
B. DIRS = DIRS + DIR
C. let I = I-1
6. return DIRS </SPAN>

Require (X) from module at path Y
1. If X is a core module,
A. return the core module
B. STOP
2. If X begins with './' or '../'
A. LOAD_AS_FILE (Y + X)
B. LOAD_AS_DIRECTORY (Y + X)
3. LOAD_NODE_MODULES (X, dirname (Y ))
4. THROW "not found"

LOAD_AS_FILE (X)
1. If X is a file, load X as JavaScript text. STOP
2. If X. js is a file, load X. js as JavaScript text. STOP
3. If X. node is a file, load X. node as binary addon. STOP

LOAD_AS_DIRECTORY (X)
1. If X/package. json is a file,
A. Parse X/package. json, and look for "main" field.
B. let M = X + (json main field)
C. LOAD_AS_FILE (M)
2. If X/index. js is a file, load X/index. js as JavaScript text. STOP
3. If X/index. node is a file, load X/index. node as binary addon. STOP

LOAD_NODE_MODULES (X, START)
1. let DIRS = NODE_MODULES_PATHS (START)
2. for each DIR in DIRS:
A. LOAD_AS_FILE (DIR/X)
B. LOAD_AS_DIRECTORY (DIR/X)

NODE_MODULES_PATHS (START)
1. let PARTS = path split (START)
2. let ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS-1
4. let DIRS = []
5. while I> ROOT,
A. if PARTS [I] = "node_modules" CONTINUE
C. DIR = path join (PARTS [0 .. I] + "node_modules ")
B. DIRS = DIRS + DIR
C. let I = I-1
6. return DIRS load the module from the global folder (loading from global folders)

If the NODE_PATH environment variable is set to an absolute path list separated by commas (,), node searches for these paths if it does not find a module elsewhere (note: in windows, NODE_PATH is a good separator .)
In addition, node will search for the path: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> 1: $ HOME/. node_modules
2: $ HOME/. node_libraries
3: $ PREFIX/lib/node </SPAN>

1: $ HOME/. node_modules
2: $ HOME/. node_libraries
3: $ PREFIX/lib/node $ HOME is the user's home directory, and $ PREFIX is the node_prefix configured by node.


These are basically some historical issues. We recommend that you put your dependencies in the node_modules folder. In this way, loading is faster and more reliable.


Accessing the main module)


When a file is executed directly from the node, then require. the main variable is set to a module object, which means you can determine whether a module runs directly during the test. [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312"> require. main === module </SPAN>

Require. main = module
For example, if foo. js is run through node foo. js, true is returned. If it is run through require ('./foo'), false is returned.
Because the module provides a filename object (normally equivalent to _ filename), the entry point of the current program can be obtained through require. main. filename.
Appendix: Package Manager Tips)

Theoretically, the require () method is designed to load reasonable file structure directories. package management programs such as dbkg, rpm, and npm can be loaded from node Modules without modification to create a local packages.
The following provides some suggested directory structures:


For example, we want to save the specified version of a package in the directory:/user/lib/node/<some-package>/<some-version>,


Packages can depend on another one. To install the foo package, you may have to install a specified version of the bar package. in addition, bar Packages may have their own dependencies. In some cases, these dependencies may conflict or form ring loading.
Since node finds the true path of each module it loads, and then, as described above, it searches for their dependencies in node_modules and uses the following structure, this is a simple solution: [javascript] view plaincopyprint?
<SPAN style = "FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">/usr/lib/node/foo/1.2.3/-Contents of the foo package, version 1.2.3.
/Usr/lib/node/bar/4.3.2/-Contents of the bar package that foo depends on.
/Usr/lib/node/foo/1.2.3/node_modules/bar-Symbolic link to/usr/lib/node/bar/4.3.2 /.
/Usr/lib/node/bar/4.3.2/node_modules/*-Symbolic links to the packages that bar depends on. </SPAN>

/Usr/lib/node/foo/1.2.3/-Contents of the foo package, version 1.2.3.
/Usr/lib/node/bar/4.3.2/-Contents of the bar package that foo depends on.
/Usr/lib/node/foo/1.2.3/node_modules/bar-Symbolic link to/usr/lib/node/bar/4.3.2 /.
/Usr/lib/node/bar/4.3.2/node_modules/*-Symbolic links to the packages that bar depends on.
Therefore, every module can obtain a version that they can use even if a ring loading or dependency conflict occurs.
In the foo package, execute require ('bar '), the bar of the specified version will be obtained through the parsed path connection character/user/lib/node/foo/1.2.3/node_modules/bar. then, when require ('quux ') is executed in the bar package, the parsed path connection character/user/lib/node/bar/4.3.2/node_modules/quux will be used to obtain the specified version of quux.
In addition, in order to make the module search process more ideal, do not directly put the package under/usr/lib/node, we can put them under/usr/lib/node_modules/<name>/<version>. in this way, node can find the packages that cannot be found under/usr/node_modules/or/node_modules without any trouble.
To ensure that the module is visible in the repl, adding/usr/lib/node_modules to the $ NODE_PATH environment variable may be effective. because all other modules used by the module are relative, and the loading of require () is based on the actual path, the package can be placed anywhere.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.