我对C ++和node / v8 Addon开发很新。
我正在尝试打包第三方C库。 一些初始化函数运行时间很长,我希望运行这些操作异步(借助libuv)。
鉴于我有以下代码:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"
//header files of 3rd party lib to be wrapped
#include "3rdparty.h"
using namespace v8;
MyObject::MyObject(void* base) : baseobject_(base) {};
MyObject::~MyObject() {};
void MyObject::Init(Handle<Object> target) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("MyObject"), constructor);
}
Handle<Value> MyObject::New(const Arguments& args) {
HandleScope scope;
if (args.IsConstructCall())
{
void* cStruct = NULL;
//
//VERY LONG TAKING OPERATION
//Want to run this async with help of libuv
createStructIn3rdPartyLib(&cStruct);
//create actual Object and pass in cStruct which becomes private field.
MyObject* obj = new MyObject(cStruct);
obj->Wrap(args.This());
return args.This();
}
return scope.Close(Undefined());
}
我希望在libuv-library的帮助下运行createStructIn3rdPartyLib(&cStruct);
。
以下是我提出的建议。不幸的是,它给了我一个分段错误,我不太确定它是否是正确的方法。 我已经查看了其他本地节点插件的来源,但没有找到任何解决我的问题的方法。 :(
欢迎任何提示。
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"
//header files of 3rd party lib to be wrapped
#include "3rdparty.h"
using namespace v8;
// libuv allows us to pass around a pointer to an arbitrary
// object when running asynchronous functions. We create a
// data structure to hold the data we need during and after
// the async work.
typedef struct AsyncData {
Persistent<Function> callback; // callback function
void *3rdpartydata
Arguments *args;
} AsyncData;
MyObject::MyObject() {};
MyObject::~MyObject() {};
void MyObject::Init(Handle<Object> target) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("MyObject"), constructor);
target->Set(String::NewSymbol("createObject"),
FunctionTemplate::New(New)->GetFunction(CreateObjectAsync));
}
Handle<Value> MyObject::New(const Arguments& args) {
HandleScope scope;
if (args.IsConstructCall())
{
void* cStruct = NULL;
//
//VERY LONG TAKING OPERATION
//Want to run this async with help of libuv
createStructIn3rdPartyLib(&cStruct);
//create actual Object and pass in cStruct which becomes private field.
MyObject* obj = new MyObject(&cStruct);
obj->Wrap(args.This());
return args.This();
}
return scope.Close(Undefined());
}
Handle<Value> MyObject::CreateObjectAsync(const Arguments& args)
{
HandleScope scope;
// create an async work token
uv_work_t *req = new uv_work_t;
// assign our data structure that will be passed around
AsyncData *asyncData = new AsyncData();
req->data = asyncData;
// expect a function as the 1st argument
// we create a Persistent reference to it so
// it won't be garbage-collected
asyncData->callback = Persistent<Function>::New(
Local<Function>::Cast(args[0]));
*(asyncData->args) = args;
// pass the work token to libuv to be run when a
// worker-thread is available to
uv_queue_work(
uv_default_loop(),
req, // work token
AsyncWork, // work function
(uv_after_work_cb)AsyncAfter // function to run when complete
);
return scope.Close(Undefined());
}
// Function to execute inside the worker-thread.
// It is not safe to access V8, or V8 data structures
// here, so everything we need for input and output
// should go on our req->data object.
void MyObject::AsyncWork(uv_work_t *req) {
// fetch our data structure
AsyncData *asyncData = (AsyncData *)req->data;
// run 3rd Party Function.
createStructIn3rdPartyLib(&asyncData->3rdpartydata);
}
// Function to execute when the async work is complete
// this function will be run inside the main event loop
// so it is safe to use V8 again
void MyObject::AsyncAfter(uv_work_t *req) {
HandleScope scope;
// fetch our data structure
AsyncData *asyncData = (AsyncData *)req->data;
// create an arguments array for the callback
MyObject *cpBase = new MyObject(asyncData->3rdpartydata);
cpBase->Wrap((*asyncData->args).This());
Handle<Value> argv[] = {Null(),(*asyncData->args).This()};
// surround in a try/catch for safety
TryCatch try_catch;
// execute the callback function
asyncData->callback->Call(Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught())
node::FatalException(try_catch);
// dispose the Persistent handle so the callback
// function can be garbage-collected
asyncData->callback.Dispose();
// clean up any memory we allocated
delete asyncData;
delete req;
}
谢谢!!!
修改 我在阅读了更多像node-ogg bindings这样的例子后,我越来越多地想到我的方法是错误的。也许我应该在C / C ++-Side上保持更低的水平,并在javascript端实现对象功能。