日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
Node.js源碼研究之模塊組織加載

粗略研究了一下node.js源碼,它有8000行C++代碼,2000行javascript代碼,來(lái)看看js和C++間是怎么組織連接起來(lái),以及各個(gè)模塊是怎樣互相調(diào)用的。

成都創(chuàng)新互聯(lián)成立與2013年,先為寧津等服務(wù)建站,寧津等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為寧津企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

本文使用的node.js版本是0.4.8,可以在https://github.com/joyent/node/tree/v0.4.8這里看到源碼。

js2c.py

node.js使用了V8附帶的js2c.py工具把所有內(nèi)置的js代碼轉(zhuǎn)換成C++里的數(shù)組,生成node_natives.h直接include到程序中,成了C++源碼的一部分。這樣做能提高內(nèi)置js模塊的編譯效率。

node.js里內(nèi)置的javascript包括了主程序src/node.js和模塊程序lib/*.js,通過(guò)js2c.py讓每一個(gè)js文件都生成一個(gè)源碼數(shù)組,存放在build/src/node_natives.h里,node_natives.h在node.js編譯后才會(huì)生成(編譯的腳本wscript中調(diào)用了js2c.py),可以看到大致的結(jié)構(gòu)如下:

 
 
 
  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. ....  

這個(gè)文件被包含在node_javascript.cc里,node_javascript.cc提供了兩個(gè)接口:

MainSource() 處理node_native源碼返回v8::Handle類(lèi)型的數(shù)據(jù)可供編譯。

DefineJavaScript(target) 把其他所有模塊源碼變成v8::Handle類(lèi)型后加載到傳入的target對(duì)象上。

所有的js模塊都被轉(zhuǎn)換成了C數(shù)組,接下來(lái)看看它們?cè)趺磮?zhí)行和互相調(diào)用。

執(zhí)行js主程序/傳遞process

先看看node.js的底層C++傳遞給javascript的一個(gè)變量process,在一開(kāi)始運(yùn)行node.js時(shí),程序會(huì)先配置好process

 
 
 
  1. Handleprocess = SetupProcessObject(argc, argv); 

然后把process作為參數(shù)去調(diào)用js主程序src/node.js返回的函數(shù),這樣process就傳遞到j(luò)avascript里了。

 
 
 
  1. //node.cc  
  2. //通過(guò)MainSource()獲取已轉(zhuǎn)化的src/node.js源碼,并執(zhí)行它  
  3. Local f_value = ExecuteString(MainSource(), IMMUTABLE_STRING("node.js"));  
  4.  
  5. //執(zhí)行src/node.js后獲得的是一個(gè)函數(shù),從node.js源碼可以看出:  
  6. //node.js  
  7. //(function(process) {  
  8. // global = this;  
  9. // ....  
  10. //})  
  11. Local f = Local::Cast(f_value);  
  12.  
  13.  
  14. //創(chuàng)建函數(shù)執(zhí)行環(huán)境,調(diào)用函數(shù),把process傳入  
  15. Localglobal = v8::Context::GetCurrent()->Global();  
  16. Local args[1] = { Local::New(process) };  
  17. f->Call(global, 1, args); 

C++模塊

node.js的模塊除了lib/*.js里用js語(yǔ)言編寫(xiě)的以外,還有一些使用C++編寫(xiě),像os/stdio/crypto/buffer等。這些模塊都通過(guò)node.h提供的NODE_MODULE方法存儲(chǔ)在變量_module里。node_extensions.cc提供了get_builtin_module(name)接口獲取這些模塊。

process.binding/C++模塊加載

process提供的一個(gè)獲取模塊的接口是binding,它的實(shí)現(xiàn)Binding()函數(shù)可以在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);  

從源碼可以看到,調(diào)用process.binding時(shí),先看緩存里是否已經(jīng)存在此模塊,不存在再調(diào)用get_builtin_module查找C++內(nèi)置模塊,找到的話獲取后綁定在exports上,在最后返回exports。

此外還有針對(duì)其他模塊的特殊處理,其中natives模塊就是調(diào)用上文提到的DefineJavaScript(exports)接口獲取到所有內(nèi)置的js模塊綁定在exports上。

現(xiàn)在在js上需要調(diào)用C++提供的模塊只需要調(diào)用process.binding就行了,例如

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

js模塊加載

src/node.js上實(shí)現(xiàn)了一個(gè)NativeModule對(duì)象用于管理js模塊,它通過(guò)調(diào)用process.binding(“natives”)把所有內(nèi)置的js模塊放在NativeModule._source上,并提供require接口供調(diào)用。在require里會(huì)給代碼加一層包裝,把一些變量傳給這個(gè)模塊。

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

再用process提供的其中一個(gè)js編譯接口process.runInThisContext執(zhí)行代碼。

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

于是在主程序src/node.js上可以調(diào)用NativeModule.require(“net”)去加載net模塊,在lib/*.js的各個(gè)js模塊里能通過(guò)調(diào)用傳進(jìn)來(lái)的require()去加載其他內(nèi)置js模塊。

總結(jié)流程

粗略總結(jié)一下加載模塊的流程:

加載C++模塊(以stdio為例):

process.binding(“stdio”) -> get_builtin_module(“stdio”) -> _module -> NODE_MODULE(node_stdio, node::Stdio::Initialize)(定義)

加載js模塊(以net為例)

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

原文:http://cnodejs.org/blog/?p=1280

【編輯推薦】

  1. 揭秘Node.js事件
  2. Node.js初探之與Mysql的交互
  3. Node.js初探之hello world
  4. Node.js入門(mén)之神秘的服務(wù)器端JavaScript
  5. 什么是Node.js?

分享標(biāo)題:Node.js源碼研究之模塊組織加載
地址分享:http://www.dlmjj.cn/article/dhgchie.html