C++与Nodejs的交互

参考链接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)


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值