gpt4 book ai didi

javascript - 如何从派生自 Nan::ObjectWrap 的类返回 native 对象?

转载 作者:IT老高 更新时间:2023-10-28 23:27:17 25 4
gpt4 key购买 nike

我有两个简单的类 AB 我试图在 node.js 的 native 模块中公开它们。 A 可以直接创建,而B 只能通过调用A::foo() 来创建。

class Internal {};

class B {
public:
Internal internal;
explicit B(Internal internal):internal(internal){}
};

class A {
public:
A() : internal() {};
B foo() { return B(internal); }
private:
Internal internal;
};

我希望能够写作:

const M = require('node_nan_minimal');
const a = new M.A();
const b = a.foo();

为此,我创建了两个从 Nan::ObjectWrap

派生的包装类
class AWrapper : public Nan::ObjectWrap { ... }
class BWrapper : public Nan::ObjectWrap { ... }

每个分别包含 AB 的实例。有了这些,我可以从 javascript 中创建 A 类型的对象,但是我在实现 AWrapper::foo 时遇到了麻烦。

static NAN_METHOD(foo) {
AWrapper* obj = Nan::ObjectWrap::Unwrap<AWrapper>(info.Holder());
B b = obj->a_.foo();
BWrapper * result = new BWrapper(b);
// Something to get a B object to javascript
// ...
// info.GetReturnValue().Set(result->Wrap());
// ...
// doesn't work - so what should it be?
}

我该怎么做才能使这个功能发挥作用?


.cc文件的完整代码是

#include <node.h>
#include <nan.h>

class Internal {
};

class B {
public:
Internal internal;
explicit B(Internal internal):internal(internal){}
};

class A {
public:
A() : internal() {};
B foo() { return B(internal); }
private:
Internal internal;
};

class BWrapper : public Nan::ObjectWrap {
public:
B b_;
explicit BWrapper(B b) : b_(b) {}
~BWrapper() {}
};


class AWrapper : public Nan::ObjectWrap {
public:
A a_;
explicit AWrapper(A a) : a_(a) {}
~AWrapper() {}

static void register_class(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("A").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);

Nan::SetPrototypeMethod(tpl, "foo", foo);

constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
Nan::Set(target, Nan::New("A").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
}

private:

static NAN_METHOD(New) {
if (info.IsConstructCall()) {
A a;
AWrapper *obj = new AWrapper(a);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
const int argc = 1;
v8::Local<v8::Value> argv[argc] = {info[0]};
v8::Local<v8::Function> cons = Nan::New(constructor());
info.GetReturnValue().Set(cons->NewInstance(argc, argv));
}
}

static NAN_METHOD(foo) {
AWrapper* obj = Nan::ObjectWrap::Unwrap<AWrapper>(info.Holder());
B b = obj->a_.foo();
BWrapper * result = new BWrapper(b);
// Something to get a B object to javascript
//...
//info.GetReturnValue().Set(result->Wrap());
}

static inline Nan::Persistent<v8::Function> & constructor() {
static Nan::Persistent<v8::Function> my_constructor;
return my_constructor;
}

};


NAN_MODULE_INIT(InitModule) {
AWrapper::register_class(target);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, InitModule);

示例的完整存储库位于 https://github.com/mikeando/node_nan_minimal您应该能够克隆然后使用 npm install 构建。

最佳答案

完成这项工作的一种方法是:

  • 向 BWrapper 添加一个构造函数,但不要将该函数暴露给 javascript。让这个函数接受一个指向 B 的指针。这需要存储在 init_class 函数中。
  • 向 BWrapper 添加一个函数以使用此构造函数创建一个新实例。这也需要一个指向 B 的指针。
  • foo 函数调用 BWrapper::NewInstance

这相当于以下补充

class BWrapper {

...

static void init_class() {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("B").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
}

static NAN_METHOD(New) {
if (!info.IsConstructCall()) {
return Nan::ThrowError("File() must be called as a constructor");
}

if (info.Length() != 1 || ! info[0]->IsExternal()) {
return Nan::ThrowError("File() can only be called internally");
}

B* b = static_cast<B*>(info[0].As<v8::External>()->Value());
BWrapper *obj = new BWrapper(*b);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}

static v8::Local<v8::Object> NewInstance(B* b) {
Nan::EscapableHandleScope scope;

const unsigned argc = 1;
v8::Local<v8::Value> argv[argc] = { Nan::New<v8::External>(b) };
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor());
v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

return scope.Escape(instance);
}

static inline Nan::Persistent<v8::Function> & constructor() {
static Nan::Persistent<v8::Function> my_constructor;
return my_constructor;
}
}

AWrapper::foo的变化是:

   static NAN_METHOD(foo) {
AWrapper* obj = Nan::ObjectWrap::Unwrap<AWrapper>(info.Holder());
B b = obj->a_.foo();
info.GetReturnValue().Set(BWrapper::NewInstance(&b));
}

最后我们需要确保类被注册。

 NAN_MODULE_INIT(InitModule) {
BWrapper::init_class();
AWrapper::register_class(target);
}

我怀疑这不是最干净的方法,我希望看到任何替代方法。我特别感兴趣的是,以这种方式将构造函数暴露给 BWrapper 是否有任何缺点。

部分内容来自阅读 https://github.com/tracelytics/node-traceview-bindings/blob/master/src/metadata.cc#L18在另一个 question 的建议下然后是我自己的一些实验。

关于javascript - 如何从派生自 Nan::ObjectWrap 的类返回 native 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48302120/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com