本文介绍在使用Node-addon-api时,能够实现用C++调用Javascript的几种方式。
比较简单,示例:
Napi::Function cb = info[0].As<Napi::Function>(); cb.Call(env.Global(), { Napi::String::New(env, "hello world") });
Return function
String MyFunction(const CallbackInfo& info) { Env env = info.Env(); return String::New(env, "hello world"); } Function CreateFunction(const CallbackInfo& info) { Env env = info.Env(); Function fn = Function::New(env, MyFunction, "funName"); return fn; }
Napi::Value callback(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); if ( info.Length() < 2 ) { throw Napi::TypeError::New( env, "Expected two arguments" ); } else if ( !info[0].IsFunction() ) { throw Napi::TypeError::New( env, "Expected first arg to be function" ); } else if ( !info[1].IsNumber() ) { throw Napi::TypeError::New( env, "Expected second arg to be number" ); } int count = info[1].As<Napi::Number>().Int32Value(); // Create a ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New( env, info[0].As<Napi::Function>(), // JavaScript function called asynchronously "Resource Name", // Name 0, // Unlimited queue 1, // Only one thread will use this initially []( Napi::Env ) { // Finalizer used to clean threads up nativeThread.join(); } ); // Create a native thread nativeThread = std::thread( [count] { auto callback = []( Napi::Env env, Napi::Function jsCallback, int* value ) { // Transform native data into JS data, passing it to the provided // `jsCallback` -- the TSFN's JavaScript function. jsCallback.Call( {Napi::Number::New( env, *value )} ); // We're finished with the data. delete value; }; for ( int i = 0; i < count; i++ ) { // Create new data int* value = new int( clock() ); // Perform a blocking call napi_status status = tsfn.BlockingCall( value, callback ); if ( status != napi_ok ) { // Handle error break; } std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); } // Release the thread-safe function tsfn.Release(); } ); return Napi::Boolean::New(env, true); }
JS:
dlxPlugin.callback(() => { console.log("C++ call javascript function"); }, 2)
Napi::Value event(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); Napi::Function emit = info[0].As<Napi::Function>(); emit.Call({ Napi::String::New(env, "msg"), Napi::Number::New(env, 1) }); emit.Call({ Napi::String::New(env, "msg"), Napi::Number::New(env, 10) }); }
JS:
const eventListener = new EventEmitter(); eventListener.on("msg", (data) => { console.log("Msg:", data); } ) event(eventListener.emit.bind(eventListener));
globalThis.num = 1; console.log(nw.test()); console.log(globalThis.num); // 2
Napi::String jsStr = Napi::String::New(env, "num++"); napi_value result; napi_run_script(env, jsStr, &result); return Napi::Value::From(env, result);
可以这样运行函数
globalThis.xx = () => { return 233; } console.log(nw.test()); // 233
Napi::String jsStr = Napi::String::New(env, "xx()");
使用eval
globalThis.num = 1; console.log(nw.test()); console.log(globalThis.num); // 2
auto eval = env.Global().Get("eval").As<Napi::Function>(); return eval.Call(env.Global(), {Napi::String::New(env, "num++")});