nodejs主线程 就一个,是用来处理js脚本,在通过c++实现addon时候,有些处理计算情形是不能放在nodejs 主线程内 ,比如常见的i/o阻塞,还有一些密集cpu消耗的计算代码。
下面是一个例子,在js 中输入参数和回调函数,等到输入参数处理完毕后,在回调中返回。 注意一下过程是在不同线程(thread)中运行,特别是
处理 已不再js主线程。
js层调用 --》
处理---》回调返回。
接口代码:hello.cc文件如下
点击(此处)折叠或打开
-
#include <node.h>
-
#include <string>
-
-
#include <sys/syscall.h>
-
#define gettid() syscall(__NR_gettid)
-
using namespace v8;
-
-
Handle<Value> async_hello(const Arguments& args);
-
-
//不在js主线程,,在uv线程池内被调用
-
void call_work(uv_work_t* req);
-
-
//回调函数
-
void call_work_after(uv_work_t* req);
-
-
-
//定义一个结构体,存储异步请求信息
-
struct Baton {
-
-
//存储回调函数,使用Persistent来声明,让系统不会在函数结束后自动回收
-
//当回调成功后,需要执行dispose释放空间
-
Persistent<Function> callback;
-
-
// 错误控制,保护错误信息和错误状态
-
bool error;
-
std::string error_message;
-
-
//存储js传入的参数,字符串
-
std::string input_string;
-
-
//存放返回参数,字符串
-
std::string result;
-
-
};
-
-
-
Handle<Value> async_hello(const Arguments& args) {
-
printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());
-
HandleScope scope;
-
if(args.Length() < 2) {
-
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
-
return scope.Close(Undefined());
-
}
-
-
-
if (!args[0]->IsString() || !args[1]->IsFunction()) {
-
return ThrowException(Exception::TypeError(
-
String::New("Wrong number of arguments")));
-
}
-
-
// 强制转换成函数变量
-
Local<Function> callback = Local<Function>::Cast(args[1]);
-
-
Baton* baton = new Baton();
-
baton->error = false;
-
baton->callback = Persistent<Function>::New(callback);
-
v8::String::Utf8Value param1(args[0]->ToString());
-
baton->input_string = std::string(*param1);
-
-
uv_work_t *req = new uv_work_t();
-
req->data = baton;
-
-
int status = uv_queue_work(uv_default_loop(), req, call_work,
-
(uv_after_work_cb)call_work_after);
-
assert(status == 0);
-
return Undefined();
-
}
-
-
//在该函数内模拟处理过程 ,如i/o阻塞或者cpu高消耗情形的处理。
-
// 注意不能使用v8 api,这个线程不是在js主线程内
-
void call_work(uv_work_t* req) {
-
printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());
-
Baton* baton = static_cast<Baton*>(req->data);
-
-
baton->result = baton->input_string+ "--->hello world from c++";
-
-
}
-
-
-
//执行完任务,进行回调的时候,返回到 js主线程
-
void call_work_after(uv_work_t* req) {
-
printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());
-
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 };
-
-
//捕捉回调中的错误,在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(String::New(baton->result.c_str()))
-
};
-
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;
-
}
-
-
void RegisterModule(Handle<Object> target) {
-
target->Set(String::NewSymbol("async_hello"),FunctionTemplate::New(async_hello)->GetFunction());
-
}
-
-
NODE_MODULE(binding, RegisterModule);
gyp文件如下
binding.gyp文件
-
{
-
'targets': [
-
{
-
'target_name': 'binding',
-
'sources': [ 'hello.cc' ],
-
'include_dirs': ['/usr/local/include','/usr/include'],
-
'libraries':['-lpthread']
-
}
-
]
-
}
js代码运行实例
test.js文件
-
var addon = require('./build/Release/binding');
-
-
addon.async_hello("good",function(err, result) {
-
console.log(result);
-
});
运行n输出结果
node test.js
-
async_hello Thread id : gettid() == 5136 //async_hello 函数在5136线程,js主线程
-
-
call_work Thread id : gettid() == 5142 //call_work 处理 函数在5142线程
-
-
call_work_after Thread id : gettid() == 5136 //call_work_after 函数在5136线程,js主线程
-
-
good--->hello world from c++ //处理函数后的输出,也是最终的输出
阅读(1508) | 评论(0) | 转发(0) |