node-addon-examples icon indicating copy to clipboard operation
node-addon-examples copied to clipboard

Wrapped Napi-extracted functions into C++ `shared_ptr<>`-s for easier lifetime management.

Open dkorolev opened this issue 4 years ago • 3 comments

Hi @gengjiawen,

Was hoping for some feedback -- after experimenting with node-addon-api for a few days looks like I've managed to wrap the extracted functions into C++ objects that do not require explicit lifetime management. Would be grateful for your time, and about as grateful if you could point me to someone else who would be better suited and/or would have more time.

A one-liner to run the code:

git clone -b cpp_thread_safe_calls https://github.com/dkorolev/node-addon-examples && (cd node-addon-examples/thread_safe_function_counting_wrapped/node-addon-api; npm i && node addon.js)

Results in:

RunAsyncWork(): calling the C++ function.
RunAsyncWork(): the promise is returned from C++.
Callback from C++: odd one=1.
Callback from C++: even two=2.
Callback from C++: odd three=3.
Callback from C++: even four=4.
Callback from C++: odd five=5.
RunAsyncWork(): the promise resolved, from C++, to true.

The relevant JavaScript piece:

const { runAsyncWork } = require('bindings')('addon');

console.log('RunAsyncWork(): calling the C++ function.');
const promise = runAsyncWork(
  (i, s) => { console.log(`Callback from C++: even ${s}=${i}.`); },
  (i, s) => { console.log(`Callback from C++: odd ${s}=${i}.`); }
);
console.log('RunAsyncWork(): the promise is returned from C++.');
promise.then((value) => { console.log(`RunAsyncWork(): the promise resolved, from C++, to ${value}.`); });

And the respective C++ one (the real code has comments, just pasting the cleaned up version here):

Napi::Value RunAsyncWork(const Napi::CallbackInfo& cbinfo) {
  NodeJSContext ctx(cbinfo);
  NodeJSFunction f_even = ctx.ExtractJSFunction(cbinfo[0]);
  NodeJSFunction f_odd = ctx.ExtractJSFunction(cbinfo[1]);
  ctx.RunAsync([f_even, f_odd]() {
    struct IntString final { int i; std::string s; };
    for (IntString& value : std::vector<IntString>({{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}, {5 ,"five"}})) {
      ((value.i % 2 == 0) ? f_even : f_odd)(value.i, value.s);
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
  });
  return ctx.GetPromise();
}

dkorolev avatar Apr 26 '21 10:04 dkorolev

@KevinEady, @gabrielschulhof would probably make sense for one or both of you to take a look at this one.

mhdawson avatar May 06 '21 21:05 mhdawson

@KevinEady, @gabrielschulhof ping

mhdawson avatar Jun 22 '21 19:06 mhdawson

@KevinEady wondering what the next step on this is?

mhdawson avatar Sep 03 '21 14:09 mhdawson