NodeJS C++ Addons基础

NodeJS C++插件是一种动态链接库,采用C/C++语言编写,可以通过require()将插件加载进NodeJS中进行使用。利用V8提供的API,可以实现JavaScript和C++的互相调用,打通JavaScript和C++之间的接口。在做一些高性能或者底层模块的时候,需要用到一些C++库,NodeJS C++插件可以帮助我们封装这些C++库的接口,使得JavaScript具备调用C++库的能力。本文将记录利用基础的V8 API编写NodeJS C++插件的过程,实现C++和JavaScript之间的参数传递、函数调用以及回调、异常处理以及对象函数传递等功能。记录过程中也会对部分概念和API进行阐述。

本文所使用的代码示例可以从该仓库中找到–【cpp-addons】

备注: 本文旨在探究NodeJS C++ Addons的原生写法,了解部分底层知识,所使用的NodeJS版本为8.11.1,由于V8原生的API会发生变动,不同版本的NodeJS的支持情况可能不同。因此不保证代码能兼容所有版本的NodeJS。

一、基本概念

1.1、hello world示例

首先通过一个简单的HelloWorld示例来了解编写C++插件的基本写法和一些API的基本概念。在示例中,C++模块向JavaScript暴露了一个hello接口,在JavaScript中调用该接口后会得到返回值hello world

#include <node.h>

namespace HelloWorldDemo {
  using v8::FunctionCallbackInfo;
  using v8::Isolate;
  using v8::Local;
  using v8::Object;
  using v8::String;
  using v8::Value;

  void hello (const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate();
    /* 通过 FunctionCallbackInfo<Value>& args 可以设置返回值 */
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world."));
  }

  void init (Local<Object> exports) {
    /* 设置模块的导出方法 hello */
    /* 等价于 js 模块中的 module.exports.hello = hello */
    NODE_SET_METHOD(exports, "hello", hello);
  }

  NODE_MODULE(NODE_GYP_MODULE_NAME, init)
}

JavaScript调用C++模块的方法时,会传递一个V8对象,类型为FunctionCallbackInfo<Value>。通过这个V8对象,JavaScript可以向C++接口传递参数,C++函数也可以通过这个对象来向JavaScript回传信息,即设置返回值。在C++接口中,通过参数const FunctionCallbackInfo<Value>& args可以拿到一个Isolate对象,Isolate代表一个V8虚拟机实例。通过args.GetIsolate()可以获取到运行JavaScript调用者的V8虚拟机实例。这个V8实例包含了内存堆,在C++接口中创建V8提供的JavaScript对象类型实例的时候会使用到。例如前面的hello world例子中,在创建一个JS字符串的时候需要传递isolate对象,表示在该V8虚拟机上创建了一个JS字符串对象,之后该字符串便可以被V8虚拟机上运行的JS调用者所使用。

Local是一个模板句柄类,Local<SomeType>代表指向某种类型的句柄。例如模块的exports属性是一个JavaScript对象,句柄类型为Local<Object>。传递给init函数的参数其实是指向相应对象的句柄。

NODE_MODULE是一个宏,设置模块初始化函数为initinit函数中执行模块的初始化,当模块第一次被加载进NodeJS应用中的时候就会执行init函数,init函数中可以设置exports属性将C++接口暴露出去给JavaScript使用。NODE_SET_METHOD用于设置属性或方法,第二个参数为属性名,第三个参数为方法对应的属性值。如果需要给exports对象设置多个属性或方法,可以调用多次NODE_SET_METHODexports对象上设置的属性方法将会作为接口暴露给外部使用。

编写NodeJS C++插件必须遵循以下这种模式:必须有一个初始化函数对模块进行初始化(设置方法属性等),然后加上NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)设置模块名和初始化函数。初始化函数可以有两种写法,第一种写法常用于设置模块的exports对象上的某个属性或方法,第二种写法可用于直接重写整个exports对象。

// 写法1
void Initialize_1(Local<Object> exports) {
  // 进行初始化...
  // example
  // 等价于js模块中的 module.exports.hello = hello
  NODE_SET_METHOD(exports, "hello", hello);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize_1)

// 写法2
void Initialize_2(Local<Object> exports, Local<Object> module) {
  // 进行初始化...
  // example
  // 等价于js模块中的 module.exports = hello
  NODE_SET_METHOD(module, "exports", hello);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize_2)

1.2、构建方法

编写完C++代码后需要将其编译构建成node文件才能够被NodeJS使用。利用node-gyp可以很方便地进行构建。首先在C++代码文件的根目录下创建一个binding.gyp文件,在文件中写入类似下面的J

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值