金华做网站公司,百度网站建设怎么联系,滁州建设局网站,网站备案需要当面核验哪些信息本作品采用知识共享署名 4.0 国际许可协议进行许可。转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.org/topic/56ed249356d74f3d3624b3ff 本博客同步在http://www.cnblogs.com/papertree/p/5285705.html 上面讲到node调用Scrip…本作品采用知识共享署名 4.0 国际许可协议进行许可。转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.org/topic/56ed249356d74f3d3624b3ff 本博客同步在http://www.cnblogs.com/papertree/p/5285705.html 上面讲到node调用Script::Compile()和Script::Run()解析执行app.js并把io操作和callback保存到default_loop_struct那么app.js里面js代码如何调用C的函数呢 在4.2节进行解释先在4.1节来点知识预热。 4.1 V8运行js代码的基础知识 —— V8的上下文 来看看google V8开发者文档的一点介绍地址https://developers.google.com/v8/get_started A context is an execution environment that allows separate, unrelated, JavaScript code to run in a single instance of V8. You must explicitly specify the context in which you want any JavaScript code to be run. 大概意思就是context上下文是用来执行javascript代码的运行环境而且运行javascript代码的时候必须指定一个context。 从文档里面摘了一段hello world代码 int main(int argc, char* argv[]) {// Initialize V8.V8::InitializeICU();V8::InitializeExternalStartupData(argv[0]);Platform* platform platform::CreateDefaultPlatform();V8::InitializePlatform(platform);V8::Initialize();// Create a new Isolate and make it the current one.ArrayBufferAllocator allocator;Isolate::CreateParams create_params;create_params.array_buffer_allocator allocator;Isolate* isolate Isolate::New(create_params);{Isolate::Scope isolate_scope(isolate);// Create a stack-allocated handle scope.HandleScope handle_scope(isolate);// Create a new context.LocalContext context Context::New(isolate);// Enter the context for compiling and running the hello world script.Context::Scope context_scope(context);// Create a string containing the JavaScript source code.LocalString source String::NewFromUtf8(isolate, Hello , World!,NewStringType::kNormal).ToLocalChecked();// Compile the source code.LocalScript script Script::Compile(context, source).ToLocalChecked();// Run the script to get the result.LocalValue result script-Run(context).ToLocalChecked();// Convert the result to an UTF8 string and print it.String::Utf8Value utf8(result);printf(%s\n, *utf8);}// Dispose the isolate and tear down V8.isolate-Dispose();V8::Dispose();V8::ShutdownPlatform();delete platform;return 0;
} 你可能会发现上面说了script-Run(context) 一定要指定一个context。那么看回3.1.2 中的图3-1-3node.cc里面的script-Run()并没有context参数。 跳到v8的源码deps/v8/src/api.cc就会发现这实际上是两个重载函数无参Script::Run()会先从Script对象取得当前的context再调用Script::Run(LocalContext context)。 图4-1-1 4.2 理解js代码如何调用C函数 —— 运行时的上下文 看个例子 左边为node 原生lib模块网络socket操作部分的文件 —— net.js我们平时使用server.listen()时最终调用到net.js里面先通过new TCP()创建一个handle对象再调用handle.listen()。而这个TCP和listen均来自左边tcp_wrap.cc文件。 也就是说通过net.js里面的handle.listen()调用了tcp_wrap.cc里面的TCPWrap::Listen()函数并且传给handle.listen()的 js参数—— backlog被包装到了C的 FunctionCallbackInfoValue类对象args。 图4-2-1 如果你第一感觉是js代码调用C代码无法理解那么一定是受到“语法”的干扰。 确实从静态的角度来看js和C是两种语言语法不互通直接在js代码调用C函数那是不可能的。 那么从动态的角度运行时来看呢别忘了任何编程语言最终运行起来都不过是进程空间里的二进制代码和数据。 图 4-2-2 4.2.1 从js代码到context 4.1 中已经讲了Script::Compile()和Script::Run() 的时候必须为 js代码指定一个运行环境context。那么 js代码和context的关联是很自然的。 4.2.2 设置C函数到context 那么上图蓝色标号1-5这几个步骤即在C代码层面把C函数设置到context的细节和相应的V8 接口是什么呢 4.3 node的js模块调用C模块的细节 在node里面在C代码里面提供给运行时javascript代码使用的无非就是这几种 1. 一个对象比如process对象上设置属性比如process.versions、或者方法比如process._kill 2. 函数对象比如TCP设置原型方法比如TCP.prototype.listen 4.3.1 process对象 —— V8的Object类 在3.2中讲到main函数启动后会加载执行src/node.js文件并且把process对象传给node.js文件在里面设置process.nextTick()等方法。 那么来看看 C如何创建一个给js使用的对象。 4.3.1.1 类型 回去3.1.2节看一下“图3-1-3”。在LoadEnvironment() 里面执行 f-Call()调用node.js里的匿名函数时传过去的process对象是通过env-process_object()获取的。 env-process_object()的实现如下 图 4-3-1 这里是个宏展开就是 inline v8::Localv8::Object Environment::process_object() const {return StrongPersistentToLocal(process_object_);
} 那么上面标红的process_object_ 成员定义如下 图 4-3-2 这里也是一个宏展开就是 class Environment {v8::Persistentv8::Object process_object_;
} 那么这里可以看到C里面提供给js代码的对象就是一个v8::Object类型的对象。 4.3.1.2 设置属性或方法 那么v8::Object类型的对象如何在C里面设置属性呢 图4-3-3 这里可以看到v8::Object类提供了Set()方法来让你设置供js访问的属性或方法。 4.3.2 TCP类 —— v8的FunctionTemplate类 那么第二种类型就是设置prototype方法。在js里面没有真正的类的概念而是通过给函数对象TCP的prototype属性设置方法使用的时候通过new TCP()去创建实例。 那么v8如何设置原型方法 4.3.2.1 设置原型方法 图4-3-4 这里可以看到通过创建一个v8::FunctionTemplate类型的对象 t通过 t-PrototypeTemplate() 去获取函数对象的prototype并进一步调用Set()去设置prototype上的方法。 最后再通过 t-GetFunction() 去获取一个该函数模版的方法。 注关于 js文件process.binding(tcp_wrap)引入TCP函数对象的机制在下一篇博客讲。 转载于:https://www.cnblogs.com/papertree/p/5285705.html