はじめに
例えば、なんか重い作業が回っていて、それが終わったら JavaScript 側で予めセットしておいた関数を呼びたい!みたいなときに使えます。
コード
ここでは関数の名前を引数にとって呼べる call 関数を作ってみます。
main.cpp
#include <iostream> #include <node.h> using namespace v8; Persistent<Object> module_target; Handle<Value> call(const Arguments& args) { HandleScope handle_scope; Local<Function> callback = Local<Function>::Cast( module_target->Get(args[0]) ); if (!callback->IsFunction()) { String::Utf8Value str(args[0]); std::cout << "Error! '" << *str << "' is not Function." << std::endl; return Undefined(); } callback->Call(module_target, 0, nullptr); } void init(Handle<Object> target) { module_target = Persistent<Object>::New(target); target->Set( String::New("call"), FunctionTemplate::New(&call)->GetFunction() ); } NODE_MODULE(call, init)
target をグローバル化してそれを登録する関数内で使用しています。lambda でも OK です。ただ、キャプチャは v8 に怒られるので出来ません。ざんねん。
#include <iostream> #include <thread> #include <node.h> using namespace v8; Persistent<Object> module_target; void init(Handle<Object> target) { module_target = Persistent<Object>::New(target); target->Set( String::New("call"), FunctionTemplate::New([](const Arguments& args)->Handle<Value> { HandleScope handle_scope; Local<Function> callback = Local<Function>::Cast( module_target->Get(args[0]) ); if (!callback->IsFunction()) { String::Utf8Value str(args[0]); std::cout << "Error! '" << *str << "' is not Function." << std::endl; return Undefined(); } callback->Call(module_target, 0, nullptr); })->GetFunction() ); } NODE_MODULE(call, init)
wscript
srcdir = '.' blddir = 'build' VERSION = '0.0.1' def set_options(opt): opt.tool_options('compiler_cxx') def configure(conf): conf.check_tool('compiler_cxx') conf.check_tool('node_addon') conf.env['CXX'] = 'g++-4.8' conf.env['CXXFLAGS'] = '-std=c++0x' def build(bld): obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') obj.target = 'call' obj.source = 'main.cpp'
test.js
var addon = require('./build/Release/call'); addon.callback = function() { console.log("hogehoge"); }; addon.call('callback');
require して貰ったオブジェクトに callback を追加します。最初、callback をグローバルに置いてしまっていて悩みました。
コンパイル & 実行
$ node-waf configure build $ (ずらーっとコンパイル結果) $ node test $ hogehoge
出来ました!ちなみに「はじめに」で言ったような重い処理のイメージは下記のようなコードになります。
#include <iostream> #include <thread> #include <node.h> using namespace v8; Persistent<Object> module_target; Handle<Value> heavy(const Arguments& args) { // 重い処理をする std::thread t([]{ std::this_thread::sleep_for(std::chrono::seconds(5)); }); t.join(); HandleScope handle_scope; Local<Function> callback = Local<Function>::Cast( module_target->Get( String::New("callback") ) ); if (!callback->IsFunction()) { std::cout << "Error! 'callback' is not declared." << std::endl; return Undefined(); } callback->Call(module_target, 0, nullptr); } void init(Handle<Object> target) { module_target = Persistent<Object>::New(target); target->Set( String::New("heavy"), FunctionTemplate::New(&heavy)->GetFunction() ); } NODE_MODULE(heavy, init)