Chinaunix首页 | 论坛 | 博客
  • 博客访问: 265548
  • 博文数量: 107
  • 博客积分: 305
  • 博客等级: 二等列兵
  • 技术积分: 417
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-22 09:42
文章分类

全部博文(107)

文章存档

2014年(3)

2013年(41)

2012年(34)

2011年(28)

2008年(1)

分类: C/C++

2013-10-24 13:42:17

原文地址:nodejs实例-异步回调实现 作者:wwm

nodejs主线程 就一个,是用来处理js脚本,在通过c++实现addon时候,有些处理计算情形是不能放在nodejs 主线程内 ,比如常见的i/o阻塞,还有一些密集cpu消耗的计算代码。
下面是一个例子,在js 中输入参数和回调函数,等到输入参数处理完毕后,在回调中返回。 注意一下过程是在不同线程(thread)中运行,特别是处理 已不再js主线程。
js层调用 --》处理---》回调返回。
 
接口代码:hello.cc文件如下
点击(此处)折叠或打开
  1. #include <node.h>
  2. #include <string>

  3. #include <sys/syscall.h>
  4. #define gettid() syscall(__NR_gettid)
  5. using namespace v8;

  6. Handle<Value> async_hello(const Arguments& args);

  7. //不在js主线程,,在uv线程池内被调用
  8. void call_work(uv_work_t* req);

  9. //回调函数
  10. void call_work_after(uv_work_t* req);


  11. //定义一个结构体,存储异步请求信息
  12. struct Baton {

  13.     //存储回调函数,使用Persistent来声明,让系统不会在函数结束后自动回收
  14.     //当回调成功后,需要执行dispose释放空间
  15.     Persistent<Function> callback;
  16.     
  17.     // 错误控制,保护错误信息和错误状态
  18.     bool error;
  19.     std::string error_message;
  20.         
  21.     //存储js传入的参数,字符串
  22.     std::string input_string;
  23.             
  24.     //存放返回参数,字符串
  25.     std::string result;
  26.         
  27. };


  28. Handle<Value> async_hello(const Arguments& args) {
  29.     printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());
  30.     HandleScope scope;
  31.     if(args.Length() < 2) {
  32.         ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
  33.         return scope.Close(Undefined());
  34.       }
  35.   
  36.   
  37.     if (!args[0]->IsString() || !args[1]->IsFunction()) {
  38.         return ThrowException(Exception::TypeError(
  39.             String::New("Wrong number of arguments")));
  40.     }
  41.     
  42.     // 强制转换成函数变量
  43.     Local<Function> callback = Local<Function>::Cast(args[1]);
  44.    
  45.     Baton* baton = new Baton();
  46.     baton->error = false;
  47.     baton->callback = Persistent<Function>::New(callback);
  48.     v8::String::Utf8Value param1(args[0]->ToString());
  49.     baton->input_string = std::string(*param1);
  50.         
  51.     uv_work_t *req = new uv_work_t();
  52.     req->data = baton;
  53.     
  54.     int status = uv_queue_work(uv_default_loop(), req, call_work,
  55.                                (uv_after_work_cb)call_work_after);
  56.     assert(status == 0);
  57.     return Undefined();
  58. }

  59. //在该函数内模拟处理过程 ,如i/o阻塞或者cpu高消耗情形的处理。
  60. // 注意不能使用v8 api,这个线程不是在js主线程内
  61. void call_work(uv_work_t* req) {
  62.       printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());
  63.     Baton* baton = static_cast<Baton*>(req->data);

  64.     baton->result = baton->input_string+ "--->hello world from c++";
  65.   
  66. }


  67. //执行完任务,进行回调的时候,返回到 js主线程
  68. void call_work_after(uv_work_t* req) {
  69. printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());    
  70.     HandleScope scope;
  71.     Baton* baton = static_cast<Baton*>(req->data);
  72.     if (baton->error) {
  73.         Local<Value> err = Exception::Error(String::New(baton->error_message.c_str()));

  74.         // 准备回调函数的参数
  75.         const unsigned argc = 1;
  76.         Local<Value> argv[argc] = { err };

  77.         //捕捉回调中的错误,在Node环境中可利用process.on('uncaughtException')捕捉错误
  78.         TryCatch try_catch;

  79.         baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
  80.         if (try_catch.HasCaught()) {
  81.             node::FatalException(try_catch);
  82.         }
  83.     } else {
  84.         
  85.         const unsigned argc = 2;
  86.         Local<Value> argv[argc] = {
  87.             Local<Value>::New(Null()),
  88.             Local<Value>::New(String::New(baton->result.c_str()))
  89.         };
  90.         TryCatch try_catch;
  91.         baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
  92.         if (try_catch.HasCaught()) {
  93.             node::FatalException(try_catch);
  94.         }
  95.     }
  96.     
  97.     //注意一定释放
  98.     baton->callback.Dispose();
  99.     // 处理完毕,清除对象和空间
  100.     delete baton;
  101.     delete req;
  102. }

  103. void RegisterModule(Handle<Object> target) {
  104.     target->Set(String::NewSymbol("async_hello"),FunctionTemplate::New(async_hello)->GetFunction());
  105. }

  106. NODE_MODULE(binding, RegisterModule);

gyp文件如下
binding.gyp文件

点击(此处)折叠或打开

  1. {
  2.   'targets': [
  3.     {
  4.       'target_name': 'binding',
  5.       'sources': [ 'hello.cc' ],
  6.        'include_dirs': ['/usr/local/include','/usr/include'],
  7.       'libraries':['-lpthread']
  8.     }
  9.   ]
  10. }

js代码运行实例
test.js文件

点击(此处)折叠或打开

  1. var addon = require('./build/Release/binding');

  2. addon.async_hello("good",function(err, result) {
  3.     console.log(result);
  4. });

运行n输出结果
node test.js

点击(此处)折叠或打开

  1. async_hello Thread id : gettid() == 5136   //async_hello 函数在5136线程,js主线程

  2. call_work Thread id : gettid() == 5142 //call_work 处理 函数在5142线程

  3. call_work_after Thread id : gettid() == 5136 //call_work_after 函数在5136线程,js主线程

  4. good--->hello world from c++                //处理函数后的输出,也是最终的输出



阅读(1288) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~