I couldn't find in the documentation and examples how to properly handle Object/Buffer/Uint8Array parameters in AsyncWorker?
The task: I'd like to receive data as Uint8Array and use it in AsyncWorker.
If I understand correctly, the data can be garbage collected.
Should I:
- Wrap object in
ObjectReferenceand pass it toAsyncWorkerconstructor? - Wrap
Uint8Arrayin ObjectReference`? - Wrap
uint8_t* dataas something?
Naive code:
#include "napi.h"
class DoHeavyMathWorker : public Napi::AsyncWorker {
public:
DoHeavyMathWorker(const Napi::Env& env, uint8_t* data)
: Napi::AsyncWorker{env, "DoHeavyMathWorker"},
m_deferred{env},
m_data{data}
{}
Napi::Promise GetPromise() { return m_deferred.Promise(); }
protected:
void Execute() {
// heavy math with data
if (m_data[0] == 0) {
m_result = 1;
} else {
m_result = 2;
}
}
void OnOK() { m_deferred.Resolve(Napi::Number::New(Env(), m_result)); }
void OnError(const Napi::Error& err) { m_deferred.Reject(err.Value()); }
private:
Napi::Promise::Deferred m_deferred;
uint8_t* m_data;
uint32_t m_result;
};
Napi::Value DoHeavyMath(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (!info[0].IsObject()) {
Napi::TypeError::New(env, "arg must be an object")
.ThrowAsJavaScriptException();
return env.Undefined();
}
Napi::Object obj = info[0].As<Napi::Object>();
uint8_t* data = obj.Get("data").As<Napi::Uint8Array>().Data();
DoHeavyMathWorker* worker = new DoHeavyMathWorker(env, data);
worker->Queue();
return worker->GetPromise();
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set("doHeavyMath", Napi::Function::New(env, DoHeavyMath));
return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
JS part:
const result = await addon.doHeavyMath({
data: new Uint8Array([42]),
});
console.log('result:', result);
- Related but not answered question: https://github.com/nodejs/node-addon-api/issues/1221
- Code is based on example https://github.com/nodejs/node-addon-examples/blob/main/src/5-async-work/async_work_promise/node-addon-api/worker.h
AsyncWorkerdocs https://github.com/nodejs/node-addon-api/blob/main/doc/async_worker.md
You have to create a persistent reference and keep it around for as long as you need the data. Note, that persistent references can only be created and destroyed on the main thread.
You should create it on the heap in the function that creates the
AsyncWorker:Pass this reference to the
AsyncWorkerand delete it in theAsyncWorkercallbacks -OnOKandOnError: