情感测试
情感测试

您现在的位置: 情感测试简介_情感测试玩法 > 情感测试答案 > Nodejs中JS是如何引用C的

Nodejs中JS是如何引用C的

发布时间:2021-5-3 19:30:16   点击数:

JavaScript使用internalBunding方法调用C++内容,看了一下大致的流程。

直接看这个文章肯定看不懂,阅读Node.js代码时看下这个会很有帮助。

全是代码,建议在较大屏幕上阅读。

C++模块暴露给JS

Node.js中C++模块的最后都会调用NODE_MODULE_CONTEXT_AWARE_INTERNAL来将该模块暴露给JavaScript,例如src/node_contextify.cc文件中,将node::contextify::Initialize作为参数调用了NODE_MODULE_CONTEXT_AWARE_INTERNAL:

NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify,node::contextify::Initialize)NODE_MODULE_CONTEXT_AWARE_INTERNAL

src/node_binding.h

#defineNODE_MODULE_CONTEXT_AWARE_CPP(modname,regfunc,priv,flags)\staticnode::node_module_module={\NODE_MODULE_VERSION,\flags,\nullptr,\__FILE__,\nullptr,\(node::addon_context_register_func)(regfunc),\NODE_STRINGIFY(modname),\priv,\nullptr};\void_register_##modname(){node_module_register(_module);}

这个宏首先创建一个node::node_module实例。

之后,生成一个*_register_##modname*函数,调用这个函数,会调用node_module_register方法。

node_module_register

src/node_binding.cc

extern"C"voidnode_module_register(void*m){structnode_module*mp=reinterpret_caststructnode_module*(m);if(mp-nm_flagsNM_F_INTERNAL){mp-nm_link=modlist_internal;modlist_internal=mp;}elseif(!node_is_initialized){//"Linked"modulesareincludedaspartofthenodeproject.//Likebuiltinstheyareregistered*before*node::Initruns.mp-nm_flags=NM_F_LINKED;mp-nm_link=modlist_linked;modlist_linked=mp;}else{thread_local_modpending=mp;}}

将模块放在模块链中。

有两个链:modlist_internal、modlist_linked。分别表示内部模块和外部模块。

internalBinding

lib/internal/bootstrap/loaders.js

JavaScript中使用internalBinding来引用C++模块。

//SetupinternalBinding()intheclosure.letinternalBinding;{constbindingObj=Object.create(null);//eslint-disable-next-lineno-global-assigninternalBinding=functioninternalBinding(module){letmod=bindingObj[module];if(typeofmod!==object){mod=bindingObj[module]=getInternalBinding(module);moduleLoadList.push(`InternalBinding${module}`);}returnmod;};}

getInternalBinding方法是C++定义的,同process等作为参数传给internal/bootstrap/loaders执行。

//BootstrapinternalloadersLocalValueloader_exports;if(!ExecuteBootstrapper(this,"internal/bootstrap/loaders",loaders_params,loaders_args).ToLocal(loader_exports)){returnMaybeLocalValue();}

internal/bootstrap/loaders返回的是这样一个对象:

constloaderExports={internalBinding,NativeModule,require:nativeModuleRequire};

其中就包含定义好的internalBinding。之后取出internal_binding_loader,调用set_internal_binding_loader。

LocalObjectloader_exports_obj=loader_exports.AsObject();LocalValueinternal_binding_loader=loader_exports_obj-Get(context(),internal_binding_string()).ToLocalChecked();CHECK(internal_binding_loader-IsFunction());set_internal_binding_loader(internal_binding_loader.AsFunction());

set_internal_binding_loader的作用是将internal_binding_loader设置在Environment上。

set_internal_binding_loader是由一个宏来定义的:

#defineV(PropertyName,TypeName)\inlinev8::LocalTypeNameEnvironment::PropertyName()const{\returnPersistentToLocal::Strong(PropertyName##_);\}\inlinevoidEnvironment::set_##PropertyName(v8::LocalTypeNamevalue){\PropertyName##_.Reset(isolate(),value);\}ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)#undefV

其中ENVIRONMENT_STRONG_PERSISTENT_VALUES里调用了V(internal_binding_loader,v8::Function):

#defineENVIRONMENT_STRONG_PERSISTENT_VALUES(V)\...\V(internal_binding_loader,v8::Function)GetInternalBinding

src/node_binding.cc

GetInternalBinding中,通过get_internal_module方法来获取到内部模块。module_v是utf8形式的字符串。

node_module*mod=get_internal_module(*module_v);

get_internal_module就是通过遍历链表来寻找模块。

之后调用InitModule方法执行模块:

exports=InitModule(env,mod,module);

InitModule方法会调用模块的nm_context_register_func方法,这个nm_context_register_func方法就是C++模块注册时传入的初始化方法。

mod-nm_context_register_func(exports,unused,env-context(),mod-nm_priv);Initialize函数的参数

所以再回到最初的C++注册方法,可以看到最终node::contextify::Initialize被调用时,传入的参数就是exports,unused,env-context(),mod-nm_priv。

NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify,node::contextify::Initialize)Mayo

大吉大利,天天开心



转载请注明:http://www.zmax-alibaba.com/qgda/137104.html

网站简介 | 发布优势 | 服务条款 | 隐私保护 | 广告合作 | 合作伙伴 | 版权申明 | 网站地图

当前时间: