参考链接addon编写
待续
#include <node.h>
#include <cstdlib>
#include <ctime>
#include <string>
using namespace v8;
// 函数返回 js 格式的 0 或 1
Handle<Value> Random(const Arguments& args) {
// 在每一个功能函数中,都会看到 HandleScope,主要是存放 handle 的容器
// 管理 handle 的内存空间,当 handlescope 被销毁的时候
// 内存将会释放,否则内存将会泄露
HandleScope scope;
// 确保函数中,在调用 scope.Close() 前都完成了出来
// 当执行完 scope.Close 后,handle 将会被清空
return scope.Close(Integer::New(rand() % 2));
}
/* 函数参数传入 */
// 返回第 N 个数的斐波拉契数列
// argument passed
Handle<Value> Fibonacci(const Arguments& args) {
HandleScope scope;
// 检查参数个数问题
if (args.Length() < 1) {
return ThrowException(Exception::TypeError(String::New("First argument must be a number")));
}
// 将js格式转换成C语言可以使用的int32_t类型
Local<Integer> integer = args[0]->ToInteger();
int32_t seq = integer->Value();
// 检测seq是否在正确值域上
if (seq < 0) {
return ThrowException(Exception::TypeError(String::New("Fibonacci sequence number must be positive")));
}
// 执行算法
int32_t current = 1;
for (int32_t previous = -1, next = 0, i = 0; i <= seq; i++){
next = previous + current;
previous = current;
current = next;
}
// 返回数值
return scope.Close(Integer::New(current));
}
/* 回调函数处理 */
Handle<Value> Callback(const Arguments& args) {
HandleScope scope;
// 确保参数是回调函数,是函数
if (!args[1]->IsFunction()) {
return ThrowException(Exception::TypeError(String::New("Second argument must be a callback function")));
}
// 强制转换成函数
Local<Function> callback = Local<Function>::Cast(args[1]);
// nodejs默认第一个参数是错误情况,第二个参数是回调函数或参与工作的参数
bool error = args[0]->BooleanValue();
if (error) {
Local<Value> err = Exception::Error(String::New("Something went wrong!"));
// 为返回的错误,创建更多的属性,数值23
err->ToObject()->Set(NODE_PSYMBOL("errno"), Integer::New(23));
// 定义回调函数的参数个数和参数数组
const unsigned argc = 1;
Local<Value> argv[argc] = {err};
// 异步回调执行 callback
callback->Call(Context::GetCurrent()->Global(), argc, argv);
} else {
// 如果执行成功,Nodejs的惯例会将第一个参数设置成null
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(Integer::New(42))
};
callback->Call(Context::GetCurrent()->Global(), argc, argv);
}
return scope.Close(Undefined()); // 异步函数,可以立即返回
}
/* 线程控制 */
// 声明函数
Handle<Value> Async(const Arguments& args);
void AsyncWork(uv_work_t* req);
void AsyncAfter(uv_work_t* req);
// 构建一个结构体存储异步工作的请求信息
struct Baton{
// 存放回调函数,使用Persisten来声明,让系统不会在函数结束后自动回收
// 当回调成功后,需要执行dispose释放空间
Persistent<Function> callback;
// 错误控制,保护错误信息和错误状态
bool error;
std::string error_message;
// 参数运行的参数
int32_t result;
};
// 函数会在nodejs当中直接被调用,它创建了一个请求的对象和等待的时间表
Handle<Value> Async(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsFunction()) {
return ThrowException(Exception::TypeError(String::New("First argument must be a callback function")));
}
// 强制将参数转换成函数变量
Local<Function> callback = Local<Function>::Cast(args[0]);
// Baton 负责管理的异步操作的状态信息,作为参数带进去异步回调数据的流程中
Baton* baton = new Baton();
baton->error = false;
baton->callback = Persistent<Function>::New(callback);
uv_work_t* req = new uv_work_t();
req->data = baton;
// 通过libuv进行操作的异步等待,可以通过libuv定义一个函数,当函数执行完成后回调
// 在此可以定义需要处理的异步流程AsyncWork和执行完异步流程后的操作AsyncAfter
int status = uv_queue_work(uv_default_loop(), req, AsyncWork, (uv_after_work_cb)AsyncAfter);
assert(status == 0);
return scope.Close(Undefined());
}
// 注意不能使用 google v8 的特性,需要用原生的C/C++来写
// 因为它是调用另外一个线程去执行任务
void AsyncWork(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data);
// 执行线程池中的工作
baton->result = 42;
}
// 执行完任务,进行回调的时候,返回到 v8/js 的线程
// 这就意味着我们需要利用 HandleScope 来管理空间
void AsyncAfter(uv_work_t* req) {
HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);
if (baton->error) {
Local<Value> err = Exception::Error(String::New(baton->error_message.c_str()));
// 准备回调函数的参数
const unsigned argc = 1;
Local<Value> argv[argc] = {err};
// 用类似 try catch 的方法,捕捉回调中的错误,在Node环境中
// 可以利用process.on('uncaughtException')捕捉错误
TryCatch try_catch;
baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(Integer::New(baton->result))
};
TryCatch try_catch;
baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
baton->callback.Dispose();
delete baton;
delete req;
}
/* 对象处理 */
// 注册模块功能,负责导出接口到 nodejs
void RegisterModule(v8::Handle<v8::Object> target) {
srand(time(NULL));
target->Set(String::NewSymbol("random"), FunctionTemplate::New(Random)->GetFunction());
target->Set(String::NewSymbol("fibonacci"), FunctionTemplate::New(Fibonacci)->GetFunction());
target->Set(String::NewSymbol("callback"), FunctionTemplate::New(Callback)->GetFunction());
target->Set(String::NewSymbol("async"), FunctionTemplate::New(Async)->GetFunction());
}
// 注册模块名称,模块将编译成modulename.node文件
NODE_MODULE(modulename, RegisterModule)