Skip to content

Commit b2b0812

Browse files
KevinEadymhdawson
authored andcommitted
AsyncWorker: make callback optional
`AsyncWorker` assumed that after work is complete, a JavaScript callback would need to execute. This change removes the restriction of specifying a `Function` callback, and instead replaces it with an `Env` parameter. Since the purpose of `receiver` was for the `this` context for the callback, it has also been removed from the constructors. Re: #231 (comment) PR-URL: #489 Reviewed-By: Michael Dawson <[email protected]>
1 parent a0cac77 commit b2b0812

File tree

6 files changed

+142
-8
lines changed

6 files changed

+142
-8
lines changed

doc/async_worker.md

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ virtual void Napi::AsyncWorker::Execute() = 0;
105105

106106
### OnOK
107107

108-
This method is invoked when the computation in the `Excecute` method ends.
109-
The default implementation runs the Callback provided when the AsyncWorker class
108+
This method is invoked when the computation in the `Execute` method ends.
109+
The default implementation runs the Callback optionally provided when the AsyncWorker class
110110
was created.
111111

112112
```cpp
@@ -149,7 +149,7 @@ explicit Napi::AsyncWorker(const Napi::Function& callback);
149149
- `[in] callback`: The function which will be called when an asynchronous
150150
operations ends. The given function is called from the main event loop thread.
151151
152-
Returns a`Napi::AsyncWork` instance which can later be queued for execution by calling
152+
Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling
153153
`Queue`.
154154
155155
### Constructor
@@ -166,7 +166,7 @@ operations ends. The given function is called from the main event loop thread.
166166
identifier for the kind of resource that is being provided for diagnostic
167167
information exposed by the async_hooks API.
168168

169-
Returns a `Napi::AsyncWork` instance which can later be queued for execution by
169+
Returns a `Napi::AsyncWorker` instance which can later be queued for execution by
170170
calling `Napi::AsyncWork::Queue`.
171171

172172
### Constructor
@@ -185,7 +185,7 @@ information exposed by the async_hooks API.
185185
- `[in] resource`: Object associated with the asynchronous operation that
186186
will be passed to possible async_hooks.
187187
188-
Returns a `Napi::AsyncWork` instance which can later be queued for execution by
188+
Returns a `Napi::AsyncWorker` instance which can later be queued for execution by
189189
calling `Napi::AsyncWork::Queue`.
190190
191191
### Constructor
@@ -200,7 +200,7 @@ explicit Napi::AsyncWorker(const Napi::Object& receiver, const Napi::Function& c
200200
- `[in] callback`: The function which will be called when an asynchronous
201201
operations ends. The given function is called from the main event loop thread.
202202

203-
Returns a `Napi::AsyncWork` instance which can later be queued for execution by
203+
Returns a `Napi::AsyncWorker` instance which can later be queued for execution by
204204
calling `Napi::AsyncWork::Queue`.
205205

206206
### Constructor
@@ -241,6 +241,54 @@ will be passed to possible async_hooks.
241241
Returns a `Napi::AsyncWork` instance which can later be queued for execution by
242242
calling `Napi::AsyncWork::Queue`.
243243

244+
245+
### Constructor
246+
247+
Creates a new `Napi::AsyncWorker`.
248+
249+
```cpp
250+
explicit Napi::AsyncWorker(Napi::Env env);
251+
```
252+
253+
- `[in] env`: The environment in which to create the `Napi::AsyncWorker`.
254+
255+
Returns an `Napi::AsyncWorker` instance which can later be queued for execution by calling
256+
`Napi::AsyncWorker::Queue`.
257+
258+
### Constructor
259+
260+
Creates a new `Napi::AsyncWorker`.
261+
262+
```cpp
263+
explicit Napi::AsyncWorker(Napi::Env env, const char* resource_name);
264+
```
265+
266+
- `[in] env`: The environment in which to create the `Napi::AsyncWorker`.
267+
- `[in] resource_name`: Null-terminated strings that represents the
268+
identifier for the kind of resource that is being provided for diagnostic
269+
information exposed by the async_hooks API.
270+
271+
Returns a `Napi::AsyncWorker` instance which can later be queued for execution by
272+
calling `Napi::AsyncWorker::Queue`.
273+
274+
### Constructor
275+
276+
Creates a new `Napi::AsyncWorker`.
277+
278+
```cpp
279+
explicit Napi::AsyncWorker(Napi::Env env, const char* resource_name, const Napi::Object& resource);
280+
```
281+
282+
- `[in] env`: The environment in which to create the `Napi::AsyncWorker`.
283+
- `[in] resource_name`: Null-terminated strings that represents the
284+
identifier for the kind of resource that is being provided for diagnostic
285+
information exposed by the async_hooks API.
286+
- `[in] resource`: Object associated with the asynchronous operation that
287+
will be passed to possible async_hooks.
288+
289+
Returns a `Napi::AsyncWorker` instance which can later be queued for execution by
290+
calling `Napi::AsyncWorker::Queue`.
291+
244292
### Destructor
245293
246294
Deletes the created work object that is used to execute logic asynchronously.

napi-inl.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,6 +3522,32 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
35223522
NAPI_THROW_IF_FAILED_VOID(_env, status);
35233523
}
35243524

3525+
inline AsyncWorker::AsyncWorker(Napi::Env env)
3526+
: AsyncWorker(env, "generic") {
3527+
}
3528+
3529+
inline AsyncWorker::AsyncWorker(Napi::Env env,
3530+
const char* resource_name)
3531+
: AsyncWorker(env, resource_name, Object::New(env)) {
3532+
}
3533+
3534+
inline AsyncWorker::AsyncWorker(Napi::Env env,
3535+
const char* resource_name,
3536+
const Object& resource)
3537+
: _env(env),
3538+
_receiver(),
3539+
_callback(),
3540+
_suppress_destruct(false) {
3541+
napi_value resource_id;
3542+
napi_status status = napi_create_string_latin1(
3543+
_env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3544+
NAPI_THROW_IF_FAILED_VOID(_env, status);
3545+
3546+
status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3547+
OnWorkComplete, this, &_work);
3548+
NAPI_THROW_IF_FAILED_VOID(_env, status);
3549+
}
3550+
35253551
inline AsyncWorker::~AsyncWorker() {
35263552
if (_work != nullptr) {
35273553
napi_delete_async_work(_env, _work);
@@ -3587,11 +3613,15 @@ inline void AsyncWorker::SuppressDestruct() {
35873613
}
35883614

35893615
inline void AsyncWorker::OnOK() {
3590-
_callback.Call(_receiver.Value(), std::initializer_list<napi_value>{});
3616+
if (!_callback.IsEmpty()) {
3617+
_callback.Call(_receiver.Value(), std::initializer_list<napi_value>{});
3618+
}
35913619
}
35923620

35933621
inline void AsyncWorker::OnError(const Error& e) {
3594-
_callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
3622+
if (!_callback.IsEmpty()) {
3623+
_callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
3624+
}
35953625
}
35963626

35973627
inline void AsyncWorker::SetError(const std::string& error) {

napi.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,13 @@ namespace Napi {
18001800
const char* resource_name,
18011801
const Object& resource);
18021802

1803+
explicit AsyncWorker(Napi::Env env);
1804+
explicit AsyncWorker(Napi::Env env,
1805+
const char* resource_name);
1806+
explicit AsyncWorker(Napi::Env env,
1807+
const char* resource_name,
1808+
const Object& resource);
1809+
18031810
virtual void Execute() = 0;
18041811
virtual void OnOK();
18051812
virtual void OnError(const Error& e);

test/asyncworker-nocallback.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
const buildType = process.config.target_defaults.default_configuration;
3+
const common = require('./common');
4+
5+
test(require(`./build/${buildType}/binding.node`));
6+
test(require(`./build/${buildType}/binding_noexcept.node`));
7+
8+
function test(binding) {
9+
const resolving = binding.asyncworker.doWorkNoCallback(true, {});
10+
resolving.then(common.mustCall()).catch(common.mustNotCall());
11+
12+
const rejecting = binding.asyncworker.doWorkNoCallback(false, {});
13+
rejecting.then(common.mustNotCall()).catch(common.mustCall());
14+
return;
15+
}

test/asyncworker.cc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,41 @@ class TestWorker : public AsyncWorker {
2929
bool _succeed;
3030
};
3131

32+
class TestWorkerNoCallback : public AsyncWorker {
33+
public:
34+
static Value DoWork(const CallbackInfo& info) {
35+
napi_env env = info.Env();
36+
bool succeed = info[0].As<Boolean>();
37+
Object resource = info[1].As<Object>();
38+
39+
TestWorkerNoCallback* worker = new TestWorkerNoCallback(env, "TestResource", resource);
40+
worker->_succeed = succeed;
41+
worker->Queue();
42+
return worker->_deferred.Promise();
43+
}
44+
45+
protected:
46+
void Execute() override {
47+
}
48+
virtual void OnOK() override {
49+
_deferred.Resolve(Env().Undefined());
50+
51+
}
52+
virtual void OnError(const Napi::Error& /* e */) override {
53+
_deferred.Reject(Env().Undefined());
54+
}
55+
56+
private:
57+
TestWorkerNoCallback(napi_env env, const char* resource_name, const Object& resource)
58+
: AsyncWorker(env, resource_name, resource), _deferred(Napi::Promise::Deferred::New(env)) {
59+
}
60+
Promise::Deferred _deferred;
61+
bool _succeed;
62+
};
63+
3264
Object InitAsyncWorker(Env env) {
3365
Object exports = Object::New(env);
3466
exports["doWork"] = Function::New(env, TestWorker::DoWork);
67+
exports["doWorkNoCallback"] = Function::New(env, TestWorkerNoCallback::DoWork);
3568
return exports;
3669
}

test/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ let testModules = [
1111
'arraybuffer',
1212
'asynccontext',
1313
'asyncworker',
14+
'asyncworker-nocallback',
1415
'asyncworker-persistent',
1516
'basic_types/array',
1617
'basic_types/boolean',

0 commit comments

Comments
 (0)