NodeJS C++ Addons之C++类实例包装与异步操作

本文是对NodeJS C++ Addons原生写法的进一步探索,介绍了利用原生的Node和V8提供的API实现类包装和异步调用的具体做法。在阅读本文之前,如果对NodeJS C++ Addons的基础不熟悉的话,建议先阅读上一篇博客【NodeJS C++ Addons基础】进行了解之后再回来阅读本文。本文所使用的代码示例可以从该仓库中找到–【cpp-addons】备注: 本文旨在探究Nod...
摘要由CSDN通过智能技术生成

本文是对NodeJS C++ Addons原生写法的进一步探索,介绍了利用原生的Node和V8提供的API实现类包装和异步调用的具体做法。在阅读本文之前,如果对NodeJS C++ Addons的基础不熟悉的话,建议先阅读上一篇博客【NodeJS C++ Addons基础】进行了解之后再回来阅读本文。

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

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

一、C++类和对象实例的包装

NodeJS C++插件除了可以向JavaScript提供函数接口之外,还可以将一些C++类或者C++对象实例包装后直接提供给JavaScript使用。举个例子,假设有个用C++实现的类,类名为SomeClass,现在想要在JavaScript中直接使用该类,通过new SomeClass(...)直接创建该类的实例并进行使用。

接下来将使用一个简单的例子来说明如何进行C++类和对象的包装。在这个例子中,将实现一个C++类Accumulator,该类是一个累加器,提供add()getAddTimes()两个方法,add()方法用于将参数累加并返回当前的累加值,getAddTimes()则是返回当前的累加次数。在创建Accumulator实例的时候,可以指定累加开始的初始值。最后,我们期望实现的效果如下,可以在JavaScript中使用这个C++类并创建该类的实例,并且可以调用该类上定义的方法。

// cpp-object-wrap demo
const AccumulatorModule = require('./build/Release/Accumulator')
let acc = new AccumulatorModule.Accumulator(2)
console.log('[ObjectWrapDemo] 2 + 12 = ' + acc.add(12))
console.log('[ObjectWrapDemo] 2 + 12 + 5 = ' + acc.add(5))
console.log('[ObjectWrapDemo] add times: ' + acc.getAddTimes())

在C++中,Accumulator是一个通过class关键字定义的普通类,而在JavaScript中,一个类即为一个JS函数。在C++中,Accumulator的实例是一个普通的C++类实例,在JavaScript中,一个实例即为一个JS对象。JS函数在V8中对应的是一个v8::Function实例,JS对象在V8中对应的是一个v8::Object实例,因此,包装要做的事情,便是将一个C++类包装成一个v8::Function实例,将一个C++实例对象包装成一个v8::Object实例,然后提供给JavaScript使用。下面是该C++插件的实现源码,注释包含了对包装过程的介绍。

#include <node.h>
#include <node_object_wrap.h>

namespace CppObjectWrapDemo {
  using v8::Context;
  using v8::Function;
  using v8::FunctionCallbackInfo;
  using v8::FunctionTemplate;
  using v8::Isolate;
  using v8::Local;
  using v8::Number;
  using v8::Object;
  using v8::Persistent;
  using v8::String;
  using v8::Value;
  using v8::Exception;

  /* 将C++类封装给JS使用,需要继承node::ObjectWrap */
  class Accumulator : public node::ObjectWrap {
    public:
      /* 初始化该类的JS构造函数,并返回JS构造函数 */
      static Local<Function> init (Isolate* isolate) {
        /* 利用函数模板,将一个C++函数包装成JS函数 */
        Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, AccumulatorJS);
        tpl->SetClassName(String::NewFromUtf8(isolate, "Accumulator"));
        tpl->InstanceTemplate()->SetInternalFieldCount(1);
        /* 类方法定义在构造函数的prototype上 */
        NODE_SET_PROTOTYPE_METHOD(tpl, "add", add);
        NODE_SET_PROTOTYPE_METHOD(tpl, "getAddTimes", getAddTimes);
        /* 获取Accumulator类的JS构造函数 */
        Local<Function> fn = tpl->GetFunction();
        /* JS构造函数句柄存储于constructor上,后续还会使用到 */
        constructor.Reset(isolate, fn);
        return fn;
      }
    private:
      /* 成员变量 */
      static Persistent<Function> constructor;
      double value;
      int addTimes;

      /* 该类的C++构造函数,设置成员变量初始值 */
      explicit Accumulator (double initValue = 0) {
        this->value = initValue;
        this->addTimes = 0;
      }

      /* 该类的JS构造函数,创建该类的对象,并包装成JS对象然后进行返回 */
      static void AccumulatorJS (const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        if (args.IsConstructCall()) {
  /* 通过 new Accumulator() 创建对象 */
          /* 提取参数数值 */
          double val = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
          /* 创建该类的实例对象 */
          Accumulator* 
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值