Comments (13)
If you have some result data to pass back from Execute()
, I'd suggest saving it to a member variable of your AsyncWorker
subclass. Then in your OnOK()
override you can pass that result data back to a JavaScript function.
I suppose we could add to the library something like an AsyncWorker<TResult>
class, that has a TResult Result()
and maybe a SetResult(TResult result)
method. But I don't know if it would very helpful since you need to subclass AsyncWorker
anyway as it is to override the OnOK()
method. So it's trivial to then define your own result member(s) when needed.
from node-addon-api.
The _test
value is invalid by the time OnOK()
runs because it got collected by the GC. To prevent that, you should store it as a Napi::ObjectReference
:
private:
Napi::ObjectReference _test;
...
_test = Napi::Persistent(Napi::Object::New(Env()));
Or you can use the Receiver()
ObjectReference
that is already attached to the AsyncWorker
instance, and set/get properties on it:
Receiver().Set("test", Napi::Object::New(Env());
from node-addon-api.
Oh, yes I forgot to mention an important detail. The Execute()
method does not run in a JavaScript context, so you can't access any JS types from there. Instead you should save any results as (non-JS) member variables, and convert the results to JS values in the OkOK()
callback.
from node-addon-api.
Sorry for adding momentum to a closed issue, but I was trying to implement the suggested solution that @jasongin mentioned above. Using non Napi::Object values like Napi::Boolean works fine, but I am trying to call the callback function with an object as second parameter and it results in segfaults and funky promises resolving in error messages 💃
Any idea what I (not that strong at C++) am doing wrong here?
// callme.cc
#include "napi.h"
namespace hello {
class HelloWorker : public Napi::AsyncWorker {
public:
HelloWorker(Napi::Function callback) : AsyncWorker(callback){
_test = Napi::Object::New(Env());
}
bool _succeed;
protected:
void Execute() override {
if(!_succeed){
SetError("Hello World Error");
} else {
//segfault here
_test.Set("test", Napi::Boolean::New(Env(), true));
}
}
private:
Napi::Object _test;
void OnOK() override {
Callback().MakeCallback(Receiver().Value(), std::initializer_list<napi_value>{
Napi::Value(), //segfault
_test //promise with: Invalid pointer passed as argument
});
}
};
void RunCallback(const Napi::CallbackInfo& info){
bool succeed = info[0].As<Napi::Boolean>();
Napi::Value data = info[1];
Napi::Function callback = info[2].As<Napi::Function>();
HelloWorker* worker = new HelloWorker(callback);
worker->Receiver().Set("data", data);
worker->_succeed = succeed;
worker->Queue();
}
Napi::Function InitCallMe(Napi::Env env){
Napi::Function runcallback_function = Napi::Function::New(env, RunCallback);
return runcallback_function;
}
} //namespace hello
from node-addon-api.
Thanks for the super fast reply @jasongin , passing the object as callback param works now.
But I still cannot do any actions inside of Execute()
Receiver().Get("any");
is a segfault already :(
// callme.cc
#include "napi.h"
namespace hello {
const char* RESULT_KEY = "result";
//AsyncWorker is an abstract helper class for thread-pooled tasks
class HelloWorker : public Napi::AsyncWorker {
public:
HelloWorker(Napi::Function callback) : AsyncWorker(callback){
Receiver().Set(RESULT_KEY, Napi::Object::New(Env()));
}
bool _succeed;
protected:
//called when first in queue and dispatched in thread
void Execute() override {
if(!_succeed){
SetError("Hello World Error");
return;
}
Receiver().Get("any"); //segfault
/*
Napi::Value value = Receiver().Get(RESULT_KEY);
Napi::Object result = value.As<Napi::Object>();
result.Set("test", Napi::Boolean::New(Env(), true)); */
}
private:
//called when Execute() does not call SetError()
void OnOK() override {
Callback().MakeCallback(Receiver().Value(), std::initializer_list<napi_value>{
Env().Null(),
Receiver().Get(RESULT_KEY)
});
}
};
void RunCallback(const Napi::CallbackInfo& info){
bool succeed = info[0].As<Napi::Boolean>();
Napi::Value data = info[1];
Napi::Function callback = info[2].As<Napi::Function>();
HelloWorker* worker = new HelloWorker(callback);
worker->Receiver().Set("data", data);
worker->_succeed = succeed;
worker->Queue();
}
Napi::Function InitCallMe(Napi::Env env){
Napi::Function runcallback_function = Napi::Function::New(env, RunCallback);
return runcallback_function;
}
} //namespace hello
from node-addon-api.
@jasongin thanks for the hint 💯 got it now :)
from node-addon-api.
If JavaScript types can only be accessed in the OnOK
callback, that means that AsyncWorker
cannot handle progressively calling a JS function, correct? For example, calling an onData
callback each time a new piece of information is available.
(I'm trying to write an addon that produces (or interfaces with) a Node readable stream).
from node-addon-api.
When using the C APIs, the void* data
parameter is the way to do it, as you described. The napi_status
parameter to the napi_async_complete_callback
is not intended to be an indication of whether the execution callback was successful, merely whether the execution was scheduled and ran (or was cancelled).
However, I'd recommend looking at the AsyncWorker
class in the C++ API instead. Async callbacks can be tricky to get correct, and the higher level of abstraction provided by the AsyncWorker
class can simplify things a lot. For example it has a SetError()
method that's meant to be called during execution, which causes a different completion callback to run: OnError()
instead of OnOK()
; the default implementation of OnError()
invokes the JS callback function with an Error
value.
Unfortunately the documentation for that class isn't written yet. (Would anyone like to help?)
from node-addon-api.
thanks @jasongin !
i'll have a crack at AsyncWorker
💃
from node-addon-api.
@jasongin How to pass "data" back to the caller from under the Execute()
method?
from node-addon-api.
@jasongin could you reply to @ptgolden's question? I can find neither node-addon-api or n-api functions to implement streaming worker
such as Nan::AsyncProgressWorker
There is example of usage from a book: [factorization example | https://github.com/freezer333/nodecpp-demo/blob/master/streaming/examples/factorization/factorization.js].
In my case I need to hook some system events and pass them to js callback.
from node-addon-api.
@gorshkov-leonid can you open a new issue. This one is closed and its probably better to discuss in a new issue.
from node-addon-api.
The
_test
value is invalid by the timeOnOK()
runs because it got collected by the GC. To prevent that, you should store it as aNapi::ObjectReference
:private: Napi::ObjectReference _test; ... _test = Napi::Persistent(Napi::Object::New(Env()));
Or you can use the
Receiver()
ObjectReference
that is already attached to theAsyncWorker
instance, and set/get properties on it:Receiver().Set("test", Napi::Object::New(Env());
I am trying something similar but it gives me an issue saying .Set is not a function
from node-addon-api.
Related Issues (20)
- Consume async JS function by TypedThreadSafeFunction ? HOT 4
- Obtain JavaScript function name from Napi::Function instance ? HOT 2
- idea: detect JS calls at compile time HOT 4
- Instantiation of ObjectWrap in c++ code causes crash HOT 3
- Just a simple question. HOT 2
- Enabling C++ exceptions on Windows is hell HOT 2
- New SemVer Major release? HOT 4
- Getting sigsegv when passing functions as parameters and building on M1 HOT 4
- Are native addons affected by Node's max memory size constraint? HOT 2
- Running single AsyncWorker at a time HOT 3
- <doc/setup.md> seems outdated HOT 1
- Query on reading/writing js typed arrays from C module. HOT 2
- Request a c++ call js demo. HOT 3
- How to properly handle `Object/Buffer/Uint8Array` in `AsyncWorker`? HOT 9
- How about add C++20 coroutine support to `Napi::Value`? HOT 9
- Node throws exception in main thread (?) when trying to execute event via ThreadSafeFunction HOT 2
- Throwing an object as an exception? HOT 3
- Napi::Value is not properly initialized the first time a program is run HOT 22
- Strange behavior HOT 2
- How do I initialize a variable of type napi_value to NULL to avoid compiler warnings HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from node-addon-api.