Node. js source code research-module organization Loading

Source: Internet
Author: User

A Rough Study of the node. js source code,It has 8000 lines of C ++ code and 2000 lines of javascript code.To see how js and C ++ are organized and connected, and how each module calls each other.

The node. js version used in this article is 0.4.8. You can see the source code in https://github.com/joyent/node/tree/v0.4.8.

Js2c. py

Node. js uses the js2c that comes with V8. the py tool converts all the built-in js Code into an array in C ++, generates node_natives.h, and directly includes it into the program, becoming part of the C ++ source code. This improves the compilation efficiency of the built-in js module.

Node. the built-in javascript in js includes the main program src/node. js and Module Program lib /*. js, through js2c. py generates a source code array for each js file, which is stored in build/src/node_natives.h and node_natives.h in node. js2c is called in the compiled wscript. py), you can see the approximate structure is as follows:

 
 
  1. namespace node {  
  2. const char node_native[] = {47, 47, 32, 67, 112 ......}  
  3. const char console_native[] = {47, 47, 32, 67, 112 ......}  
  4. const char buffer_native[] = {47, 47, 32, 67, 112 ......}  
  5. .....  
  6. }  
  7. struct _native { const char* name; const char* source; size_t source_len;};  
  8. static const struct _native natives[] = {  
  9. { "node", node_native, sizeof(node_native)-1 },  
  10. { "dgram", dgram_native, sizeof(dgram_native)-1 },  
  11. { "console", console_native, sizeof(console_native)-1 },  
  12. { "buffer", buffer_native, sizeof(buffer_native)-1 },  
  13. ....  

This file is included in node_javascript.cc. node_javascript.cc provides two interfaces:

MainSource () processes node_native source code and returns v8: Handle type data for compilation.

DefineJavaScript (target) converts the source code of all other modules into the v8: Handle type and loads it to the input target object.

All js modules are converted into C arrays. Next, let's see how they are executed and called each other.

Execute the js main program/pass the process

First, let's take a look at the underlying C ++ variable process passed to javascript by node. js. When you start running node. js, the program configures process first.

 
 
  1. Handleprocess = SetupProcessObject(argc, argv); 

Then, process is used as a parameter to call the function returned by the js main program src/node. js, so that process is passed to javascript.

 
 
  1. // Node. cc
  2. // Obtain the converted src/node. js source code through MainSource () and execute it
  3. Local f_value = ExecuteString (MainSource (), IMMUTABLE_STRING ("node. js "));
  4.  
  5. // After src/node. js is executed, a function is obtained, which can be seen from the node. js source code:
  6. // Node. js
  7. // (Function (process ){
  8. // Global = this;
  9. //....
  10. //})
  11. Local f = Local: Cast (f_value );
  12.  
  13.  
  14. // Create a function execution environment, call the function, and pass the process
  15. Localglobal = v8: Context: GetCurrent ()-> Global ();
  16. Local args [1] = {Local: New (process )};
  17. F-> Call (global, 1, args );

C ++ Module

Node. js modules are not only written in lib/*. js but also in C ++, such as OS/stdio/crypto/buffer. These modules are stored in the Variable _ module through the NODE_MODULE method provided by node. h. Node_extensions.cc provides the get_builtin_module (name) interface to obtain these modules.

Process. binding/C ++ module Loading

The interface provided by process to obtain a module is binding. Its implementation of the Binding () function can be found in node. cc.

 
 
  1. Persistent binding_cache;  
  2. static Handle Binding(const Arguments& args) {  
  3. HandleScope scope;  
  4. Local module = args[0]->ToString();  
  5. String::Utf8Value module_v(module);  
  6. node_module_struct* modp;  
  7.  
  8. if (binding_cache.IsEmpty()) {  
  9. binding_cache = Persistent::New(Object::New());  
  10. }  
  11. Local exports;  
  12. if (binding_cache->Has(module)) {  
  13. exports = binding_cache->Get(module)->ToObject();  
  14.  
  15. } else if ((modp = get_builtin_module(*module_v)) != NULL) {  
  16. exports = Object::New();  
  17. modp->register_func(exports);  
  18. binding_cache->Set(module, exports);  
  19.  
  20. } else if (!strcmp(*module_v, "constants")) {  
  21. exports = Object::New();  
  22. DefineConstants(exports);  
  23. binding_cache->Set(module, exports);  
  24.  
  25. #ifdef __POSIX__  
  26. } else if (!strcmp(*module_v, "io_watcher")) {  
  27. exports = Object::New();  
  28. IOWatcher::Initialize(exports);  
  29. binding_cache->Set(module, exports);  
  30. #endif  
  31.  
  32. } else if (!strcmp(*module_v, "natives")) {  
  33. exports = Object::New();  
  34. DefineJavaScript(exports);  
  35. binding_cache->Set(module, exports);  
  36.  
  37.  
  38. } else {  
  39. return ThrowException(Exception::Error(String::New("No such module")));  
  40. }  
  41. return scope.Close(exports);  

From the source code, we can see that process is called. when binding, check whether this module already exists in the cache. If it does not exist, call get_builtin_module to find the C ++ built-in module. If it is found, bind it to exports and return exports.

The natives module calls the DefineJavaScript (exports) interface mentioned above to obtain all the built-in js modules bound to exports.

Now, you only need to call process. binding to call the modules provided by C ++ in js. For example

 
 
  1. var stdio = process.binding("stdio") 

Js module Loading

Src/node. js implements an NativeModule object for managing the js module. It calls process. binding ("natives") places all built-in js modules in the NativeModule. _ source, and provides the require interface for calling. In require, code is encapsulated and some variables are passed to this module.

 
 
  1. NativeModule.wrapper = [  
  2. '(function (exports, require, module, __filename, __dirname) { ',  
  3. '\n});' 
  4. ]; 

Use one of the js compilation interfaces provided by process to compile process. runInThisContext to execute the code.

 
 
  1. var fn = runInThisContext(source, this.filename, true);  
  2. fn(this.exports, NativeModule.require, this, this.filename); 

So in the main program src/node. nativeModule can be called on js. require ("net") to load the net module, in lib /*. each js module of js can load other built-in js modules by calling the passed require.

Summary Process

A rough summary of the process of loading modules:

Load the C ++ module (take stdio as an example ):

Process. binding ("stdio")-> get_builtin_module ("stdio")-> _ module-> NODE_MODULE (node_stdio, node: Stdio: Initialize) (defined)

Loading js modules (take net as an example)

Require ("net")-> NativeModule. require ("net")-> process. binding ("natives") ["net"]-> DefineJavaScript ()-> natives []-> node_natives.h

Http://cnodejs.org/blog? P = 1280

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.