node中javascript调用c++实现过程分析
2014-10-21 10:59
549 查看
先做这样的约定,node提供的模块,称为核心模块。用户编写的模块,称为文件模块。Node中那些由纯c/c++编写的模块称为内建模块。Node中buffer crypto evals fs os 等都是部分通过c/c++编写的。
内建模块内部的数据结构
在内建模块在定义之后,通过NODE_MODULE将模块定义到node命名空间中去:
简单点来讲就是将某个模块方法放到了node_module_struct的实例中的register_func成员中。这里一般是模块初始化方法。
在node_extensions.h中将那些内建模块统一放进了node_module_list的数组中。
这样之后,就能够从node_module_list中取出我们想要的模块信息了。
在node启动时,会生成全局的process,并调用bind方法来加载内建模块。
创建了exports对象,然后调用get_builtin_module方法去获取内建对象,再使用register_func(就是NODE_MODULE中的第二个参数)去填充exports对象,然后缓存exports对象,并返回给调用方完成导出。这里register_func函数是比较重要的,它到底是个什么函数呢?
我们看看node_file.cc中的register_func:
NODE_MODULE(node_fs,node::InitFs)
node::InitFs函数
可以看到这里做的最主要的工作就是给传入的对象target添加各种各样的方法。比如:
这样完成了c++方法挂载带了exports对象上,调用者就能够轻松调用了。后续的工作应该是要借助v8完成javascript调用c++。
内建模块内部的数据结构
struct node_module_struct { intversion; void *dso_handle; const char *filename; node::addon_register_func register_func; const char *modname; };
在内建模块在定义之后,通过NODE_MODULE将模块定义到node命名空间中去:
#define NODE_MODULE(modname, regfunc) \ extern "C" { \ NODE_MODULE_EXPORT node::node_module_struct modname ## _module = \ { \ NODE_STANDARD_MODULE_STUFF, \ (node::addon_register_func)regfunc, \ NODE_STRINGIFY(modname) \ }; \ }
简单点来讲就是将某个模块方法放到了node_module_struct的实例中的register_func成员中。这里一般是模块初始化方法。
在node_extensions.h中将那些内建模块统一放进了node_module_list的数组中。
NODE_EXT_LIST_START NODE_EXT_LIST_ITEM(node_buffer) #if H***E_OPENSSL NODE_EXT_LIST_ITEM(node_crypto) #endif NODE_EXT_LIST_ITEM(node_evals) NODE_EXT_LIST_ITEM(node_fs) NODE_EXT_LIST_ITEM(node_http_parser) NODE_EXT_LIST_ITEM(node_os) NODE_EXT_LIST_ITEM(node_zlib) // libuv rewrite NODE_EXT_LIST_ITEM(node_timer_wrap) NODE_EXT_LIST_ITEM(node_tcp_wrap) NODE_EXT_LIST_ITEM(node_udp_wrap) NODE_EXT_LIST_ITEM(node_pipe_wrap) NODE_EXT_LIST_ITEM(node_cares_wrap) NODE_EXT_LIST_ITEM(node_tty_wrap) NODE_EXT_LIST_ITEM(node_process_wrap) NODE_EXT_LIST_ITEM(node_fs_event_wrap) NODE_EXT_LIST_ITEM(node_signal_wrap) NODE_EXT_LIST_END
这样之后,就能够从node_module_list中取出我们想要的模块信息了。
在node启动时,会生成全局的process,并调用bind方法来加载内建模块。
static Handle<Value> Binding(constArguments& args) { HandleScope scope; Local<String> module = args[0]->ToString(); node::Utf8Valuemodule_v(module); node_module_struct* modp; if(binding_cache.IsEmpty()) { binding_cache = Persistent<Object>::New(Object::New()); } Local<Object> exports; if(binding_cache->Has(module)) { exports = binding_cache->Get(module)->ToObject(); return scope.Close(exports); } //Append a string to process.moduleLoadList char buf[1024]; snprintf(buf, 1024, "Binding %s", *module_v); uint32_t l = module_load_list->Length(); module_load_list->Set(l, String::New(buf)); if((modp = get_builtin_module(*module_v)) != NULL) { exports = Object::New(); // Internal bindings don't have a "module" object, // only exports. modp->register_func(exports, Undefined()); binding_cache->Set(module, exports); }else if (!strcmp(*module_v, "constants")) { exports = Object::New(); DefineConstants(exports); binding_cache->Set(module, exports); }else if (!strcmp(*module_v, "natives")) { exports = Object::New(); DefineJavaScript(exports); binding_cache->Set(module, exports); }else { return ThrowException(Exception::Error(String::New("No suchmodule"))); } return scope.Close(exports); }
创建了exports对象,然后调用get_builtin_module方法去获取内建对象,再使用register_func(就是NODE_MODULE中的第二个参数)去填充exports对象,然后缓存exports对象,并返回给调用方完成导出。这里register_func函数是比较重要的,它到底是个什么函数呢?
我们看看node_file.cc中的register_func:
NODE_MODULE(node_fs,node::InitFs)
node::InitFs函数
void InitFs(Handle<Object> target) { HandleScope scope; //Initialize the stats object Local<FunctionTemplate> stat_templ = FunctionTemplate::New(); stats_constructor_template =Persistent<FunctionTemplate>::New(stat_templ); target->Set(String::NewSymbol("Stats"),//由v8引擎完成添加方法 stats_constructor_template->GetFunction()); File::Initialize(target); oncomplete_sym = NODE_PSYMBOL("oncomplete"); StatWatcher::Initialize(target);// 由 v8引擎完成添加方法 }
可以看到这里做的最主要的工作就是给传入的对象target添加各种各样的方法。比如:
NODE_SET_METHOD(target, "close",Close); NODE_SET_METHOD(target, "open", Open); NODE_SET_METHOD(target, "read",Read); NODE_SET_METHOD(target, "fdatasync", Fdatasync); NODE_SET_METHOD(target, "fsync", Fsync); NODE_SET_METHOD(target, "rename", Rename); NODE_SET_METHOD(target, "ftruncate", FTruncate); NODE_SET_METHOD(target, "rmdir", RMDir); NODE_SET_METHOD(target, "mkdir", MKDir); NODE_SET_METHOD(target, "readdir", ReadDir); NODE_SET_METHOD(target, "stat", Stat); NODE_SET_METHOD(target, "lstat", LStat); NODE_SET_METHOD(target, "fstat", FStat); NODE_SET_METHOD(target, "link", Link); NODE_SET_METHOD(target, "symlink", Symlink); NODE_SET_METHOD(target, "readlink", ReadLink); NODE_SET_METHOD(target, "unlink", Unlink); NODE_SET_METHOD(target, "write", Write); NODE_SET_METHOD(target, "chmod", Chmod); NODE_SET_METHOD(target, "fchmod", FChmod); //NODE_SET_METHOD(target, "lchmod", LChmod); NODE_SET_METHOD(target, "chown", Chown); NODE_SET_METHOD(target, "fchown", FChown); //NODE_SET_METHOD(target, "lchown", LChown); NODE_SET_METHOD(target, "utimes", UTimes); NODE_SET_METHOD(target, "futimes", FUTimes);
这样完成了c++方法挂载带了exports对象上,调用者就能够轻松调用了。后续的工作应该是要借助v8完成javascript调用c++。
相关文章推荐
- C/C++—— 在构造函数中调用虚函数能实现多态吗(Vptr指针初始化的过程分析)
- 使用CDHtmlDialog ,实现javascript 调用C++
- 韩顺平_轻松搞定网页设计(html+css+javascript)_第26讲_js函数调用过程内存分析_js函数细节_学习笔记_源代码图解_PPT文档整理
- 韩顺平 javascript教学视频_学习笔记9_js函数调用过程内存分析_js函数细节
- 利用Anthem.net 实现前台javascript调用服务器端c#函数 及流程分析
- 编译原理(八) 算符优先分析法(分析过程的算法和C++实现)
- 利用Anthem.net 实现前台javascript调用服务器端c#函数 及流程分析
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为(转)
- 编译原理(六) LL(1)文法分析法(分析过程的C++实现)
- 在Electron中通过ffi模块实现JavaScript调用C++动态库
- node.js利用javascript中构造函数继承,实现模块调用
- appweb的JavaScript调用C函数的实现过程(以设置eth0 IP地址为例)
- Lua栈介绍及C++调用Lua过程分析
- 【C++进阶】C++函数调用过程深入分析
- c与c++相互调用机制分析与实现
- 用Javascript调用ASP实现过程
- linux系统下,c++程序,调用system命令失败,分析过程
- printf_系统调用过程分析_write() putc() 函数实现
- linux下c++调用java实现过程
- c++中六种构造函数的实现以及9中情况下,构造函数的调用过程