下面是一个例子,在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++ //处理函数后的输出,也是最终的输出