Skip to content

Commit e1e5e6f

Browse files
committed
src: make OnWorkComplete and OnExecute override-able
1 parent 295e560 commit e1e5e6f

File tree

3 files changed

+164
-80
lines changed

3 files changed

+164
-80
lines changed

doc/async_worker.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,30 @@ class was created, passing in the error as the first parameter.
136136
virtual void Napi::AsyncWorker::OnError(const Napi::Error& e);
137137
```
138138

139+
### OnWorkComplete
140+
141+
This method is invoked after the work has completed on JavaScript thread.
142+
The default implementation of this method checks the status of the work and
143+
try to dispatch the result to `Napi::AsyncWorker::OnOk` or `Napi::AsyncWorker::Error`
144+
if the work has committed an error. If the work was cancelled, neither of
145+
`Napi::AsyncWorker::OnOk` nor `Napi::AsyncWorker::Error` will be invoked.
146+
After the result dispatched, the default implementation will call into
147+
`Napi::AsyncWorker::Destroy` if `SuppressDestruct()` was not called.
148+
149+
```cpp
150+
virtual void OnWorkComplete(Napi::Env env, napi_status status);
151+
```
152+
153+
### OnExecute
154+
155+
This method is invoked immediately on the work thread on scheduled.
156+
The default implementation of this method just call the `Napi::AsyncWorker::Execute`
157+
and handles exceptions if cpp exceptions was enabled.
158+
159+
```cpp
160+
virtual void OnExecute(Napi::Env env);
161+
```
162+
139163
### Destroy
140164

141165
This method is invoked when the instance must be deallocated. If

napi-inl.h

Lines changed: 80 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3699,8 +3699,8 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
36993699
_env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
37003700
NAPI_THROW_IF_FAILED_VOID(_env, status);
37013701

3702-
status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3703-
OnWorkComplete, this, &_work);
3702+
status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
3703+
OnAsyncWorkComplete, this, &_work);
37043704
NAPI_THROW_IF_FAILED_VOID(_env, status);
37053705
}
37063706

@@ -3725,8 +3725,8 @@ inline AsyncWorker::AsyncWorker(Napi::Env env,
37253725
_env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
37263726
NAPI_THROW_IF_FAILED_VOID(_env, status);
37273727

3728-
status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3729-
OnWorkComplete, this, &_work);
3728+
status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
3729+
OnAsyncWorkComplete, this, &_work);
37303730
NAPI_THROW_IF_FAILED_VOID(_env, status);
37313731
}
37323732

@@ -3813,40 +3813,51 @@ inline void AsyncWorker::SetError(const std::string& error) {
38133813
inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
38143814
return {};
38153815
}
3816+
// The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT
3817+
// use it within this method, as it does not run on the main thread and must
3818+
// not run any method that would cause JavaScript to run. In practice, this
3819+
// means that almost any use of napi_env will be incorrect.
3820+
inline void OnAsyncWorkExecute(napi_env env, void* asyncworker) {
3821+
AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
3822+
self->OnExecute(env);
3823+
}
38163824
// The OnExecute method receives an napi_env argument. However, do NOT
38173825
// use it within this method, as it does not run on the main thread and must
38183826
// not run any method that would cause JavaScript to run. In practice, this
38193827
// means that almost any use of napi_env will be incorrect.
3820-
inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) {
3821-
AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
3828+
inline void AsyncWorker::OnExecute(Napi::Env /*DO_NOT_USE*/) {
38223829
#ifdef NAPI_CPP_EXCEPTIONS
38233830
try {
3824-
self->Execute();
3831+
this->Execute();
38253832
} catch (const std::exception& e) {
3826-
self->SetError(e.what());
3833+
this->SetError(e.what());
38273834
}
38283835
#else // NAPI_CPP_EXCEPTIONS
3829-
self->Execute();
3836+
this->Execute();
38303837
#endif // NAPI_CPP_EXCEPTIONS
38313838
}
38323839

3833-
inline void AsyncWorker::OnWorkComplete(
3834-
napi_env /*env*/, napi_status status, void* this_pointer) {
3835-
AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
3840+
inline void OnAsyncWorkComplete(napi_env env,
3841+
napi_status status,
3842+
void* asyncworker) {
3843+
AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
3844+
self->OnWorkComplete(env, status);
3845+
}
3846+
inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
38363847
if (status != napi_cancelled) {
3837-
HandleScope scope(self->_env);
3848+
HandleScope scope(this->_env);
38383849
details::WrapCallback([&] {
3839-
if (self->_error.size() == 0) {
3840-
self->OnOK();
3850+
if (this->_error.size() == 0) {
3851+
this->OnOK();
38413852
}
38423853
else {
3843-
self->OnError(Error::New(self->_env, self->_error));
3854+
this->OnError(Error::New(this->_env, this->_error));
38443855
}
38453856
return nullptr;
38463857
});
38473858
}
3848-
if (!self->_suppress_destruct) {
3849-
self->Destroy();
3859+
if (!this->_suppress_destruct) {
3860+
this->Destroy();
38503861
}
38513862
}
38523863

@@ -4172,9 +4183,38 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
41724183
}
41734184

41744185
////////////////////////////////////////////////////////////////////////////////
4175-
// Async Progress Worker class
4186+
// Async Progress Worker Base class
41764187
////////////////////////////////////////////////////////////////////////////////
4188+
inline AsyncProgressWorkerBase::AsyncProgressWorkerBase(const Object& receiver,
4189+
const Function& callback,
4190+
const char* resource_name,
4191+
const Object& resource)
4192+
: AsyncWorker(receiver, callback, resource_name, resource) {
4193+
_tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
4194+
}
41774195

4196+
#if NAPI_VERSION > 4
4197+
inline AsyncProgressWorkerBase::AsyncProgressWorkerBase(Napi::Env env,
4198+
const char* resource_name,
4199+
const Object& resource)
4200+
: AsyncWorker(env, resource_name, resource) {
4201+
// TODO: Once the changes to make the callback optional for threadsafe
4202+
// functions are no longer optional we can remove the dummy Function here.
4203+
Function callback;
4204+
_tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
4205+
}
4206+
#endif
4207+
4208+
inline void OnAsyncWorkProgress(Napi::Env /* env */,
4209+
Napi::Function /* jsCallback */,
4210+
void* asyncworker) {
4211+
AsyncProgressWorkerBase* asyncprogressworker = static_cast<AsyncProgressWorkerBase*>(asyncworker);
4212+
asyncprogressworker->OnWorkProgress();
4213+
}
4214+
4215+
////////////////////////////////////////////////////////////////////////////////
4216+
// Async Progress Worker class
4217+
////////////////////////////////////////////////////////////////////////////////
41784218
template<class T>
41794219
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
41804220
: AsyncProgressWorker(callback, "generic") {
@@ -4198,14 +4238,14 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
41984238

41994239
template<class T>
42004240
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4201-
const Function& callback)
4241+
const Function& callback)
42024242
: AsyncProgressWorker(receiver, callback, "generic") {
42034243
}
42044244

42054245
template<class T>
42064246
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4207-
const Function& callback,
4208-
const char* resource_name)
4247+
const Function& callback,
4248+
const char* resource_name)
42094249
: AsyncProgressWorker(receiver,
42104250
callback,
42114251
resource_name,
@@ -4217,10 +4257,9 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
42174257
const Function& callback,
42184258
const char* resource_name,
42194259
const Object& resource)
4220-
: AsyncWorker(receiver, callback, resource_name, resource),
4260+
: AsyncProgressWorkerBase(receiver, callback, resource_name, resource),
42214261
_asyncdata(nullptr),
42224262
_asyncsize(0) {
4223-
_tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
42244263
}
42254264

42264265
#if NAPI_VERSION > 4
@@ -4231,35 +4270,31 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
42314270

42324271
template<class T>
42334272
inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4234-
const char* resource_name)
4273+
const char* resource_name)
42354274
: AsyncProgressWorker(env, resource_name, Object::New(env)) {
42364275
}
42374276

42384277
template<class T>
42394278
inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4240-
const char* resource_name,
4241-
const Object& resource)
4242-
: AsyncWorker(env, resource_name, resource),
4279+
const char* resource_name,
4280+
const Object& resource)
4281+
: AsyncProgressWorkerBase(env, resource_name, resource),
42434282
_asyncdata(nullptr),
42444283
_asyncsize(0) {
4245-
// TODO: Once the changes to make the callback optional for threadsafe
4246-
// functions are no longer optional we can remove the dummy Function here.
4247-
Function callback;
4248-
_tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
42494284
}
42504285
#endif
42514286

42524287
template<class T>
42534288
inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
42544289
// Abort pending tsfn call.
42554290
// Don't send progress events after we've already completed.
4256-
_tsfn.Abort();
4291+
this->_tsfn.Abort();
42574292
{
4258-
std::lock_guard<std::mutex> lock(_mutex);
4293+
std::lock_guard<std::mutex> lock(this->_mutex);
42594294
_asyncdata = nullptr;
42604295
_asyncsize = 0;
42614296
}
4262-
_tsfn.Release();
4297+
this->_tsfn.Release();
42634298
}
42644299

42654300
template<class T>
@@ -4269,20 +4304,18 @@ inline void AsyncProgressWorker<T>::Execute() {
42694304
}
42704305

42714306
template<class T>
4272-
inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) {
4273-
AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data);
4274-
4307+
inline void AsyncProgressWorker<T>::OnWorkProgress() {
42754308
T* data;
42764309
size_t size;
42774310
{
4278-
std::lock_guard<std::mutex> lock(self->_mutex);
4279-
data = self->_asyncdata;
4280-
size = self->_asyncsize;
4281-
self->_asyncdata = nullptr;
4282-
self->_asyncsize = 0;
4311+
std::lock_guard<std::mutex> lock(this->_mutex);
4312+
data = this->_asyncdata;
4313+
size = this->_asyncsize;
4314+
this->_asyncdata = nullptr;
4315+
this->_asyncsize = 0;
42834316
}
42844317

4285-
self->OnProgress(data, size);
4318+
this->OnProgress(data, size);
42864319
delete[] data;
42874320
}
42884321

@@ -4293,19 +4326,19 @@ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
42934326

42944327
T* old_data;
42954328
{
4296-
std::lock_guard<std::mutex> lock(_mutex);
4329+
std::lock_guard<std::mutex> lock(this->_mutex);
42974330
old_data = _asyncdata;
42984331
_asyncdata = new_data;
42994332
_asyncsize = count;
43004333
}
4301-
_tsfn.NonBlockingCall(this, WorkProgress_);
4334+
this->_tsfn.NonBlockingCall(this, OnAsyncWorkProgress);
43024335

43034336
delete[] old_data;
43044337
}
43054338

43064339
template<class T>
43074340
inline void AsyncProgressWorker<T>::Signal() const {
4308-
_tsfn.NonBlockingCall(this, WorkProgress_);
4341+
this->_tsfn.NonBlockingCall(this, OnAsyncWorkProgress);
43094342
}
43104343

43114344
template<class T>
@@ -4317,7 +4350,6 @@ template<class T>
43174350
inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
43184351
_worker->SendProgress_(data, count);
43194352
}
4320-
43214353
#endif
43224354

43234355
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)