Skip to content

Commit 53de2e1

Browse files
committed
n-api: Context for custom async operations
- Add napi_async_context opaque pointer type. (If needed, we could later add APIs for getting the async IDs out of this context.) - Add napi_async_init() and napi_async_destroy() APIs. - Add async_context parameter to napi_make_callback(). - Add code and checks to test_make_callback to validate async context APIs by checking async hooks are called with correct context. - Update API documentation. Fixes: #13254
1 parent 99c478e commit 53de2e1

File tree

8 files changed

+252
-97
lines changed

8 files changed

+252
-97
lines changed

doc/api/n-api.md

Lines changed: 133 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ The documentation for N-API is structured as follows:
4141
* [Working with JavaScript Properties][]
4242
* [Working with JavaScript Functions][]
4343
* [Object Wrap][]
44-
* [Asynchronous Operations][]
44+
* [Simple Asynchronous Operations][]
45+
* [Custom Asynchronous Operations][]
4546
* [Promises][]
4647

4748
The N-API is a C API that ensures ABI stability across Node.js versions
@@ -263,7 +264,7 @@ It is intended only for logging purposes.
263264
added: v8.0.0
264265
-->
265266
```C
266-
NAPI_EXTERN napi_status
267+
napi_status
267268
napi_get_last_error_info(napi_env env,
268269
const napi_extended_error_info** result);
269270
```
@@ -514,8 +515,8 @@ This API returns a JavaScript RangeError with the text provided.
514515
added: v8.0.0
515516
-->
516517
```C
517-
NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env,
518-
napi_value* result);
518+
napi_status napi_get_and_clear_last_exception(napi_env env,
519+
napi_value* result);
519520
```
520521

521522
- `[in] env`: The environment that the API is invoked under.
@@ -530,7 +531,7 @@ This API returns true if an exception is pending.
530531
added: v8.0.0
531532
-->
532533
```C
533-
NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result);
534+
napi_status napi_is_exception_pending(napi_env env, bool* result);
534535
```
535536

536537
- `[in] env`: The environment that the API is invoked under.
@@ -550,7 +551,7 @@ thrown to immediately terminate the process.
550551
added: v8.2.0
551552
-->
552553
```C
553-
NAPI_EXTERN NAPI_NO_RETURN void napi_fatal_error(const char* location, const char* message);
554+
NAPI_NO_RETURN void napi_fatal_error(const char* location, const char* message);
554555
```
555556

556557
- `[in] location`: Optional location at which the error occurred.
@@ -717,10 +718,10 @@ reverse order from which they were created.
717718
added: v8.0.0
718719
-->
719720
```C
720-
NAPI_EXTERN napi_status napi_escape_handle(napi_env env,
721-
napi_escapable_handle_scope scope,
722-
napi_value escapee,
723-
napi_value* result);
721+
napi_status napi_escape_handle(napi_env env,
722+
napi_escapable_handle_scope scope,
723+
napi_value escapee,
724+
napi_value* result);
724725
```
725726

726727
- `[in] env`: The environment that the API is invoked under.
@@ -1468,10 +1469,10 @@ of the ECMAScript Language Specification.
14681469
added: v8.0.0
14691470
-->
14701471
```C
1471-
NAPI_EXTERN napi_status napi_create_string_latin1(napi_env env,
1472-
const char* str,
1473-
size_t length,
1474-
napi_value* result);
1472+
napi_status napi_create_string_latin1(napi_env env,
1473+
const char* str,
1474+
size_t length,
1475+
napi_value* result);
14751476
```
14761477

14771478
- `[in] env`: The environment that the API is invoked under.
@@ -1801,11 +1802,11 @@ JavaScript Number
18011802
added: v8.0.0
18021803
-->
18031804
```C
1804-
NAPI_EXTERN napi_status napi_get_value_string_latin1(napi_env env,
1805-
napi_value value,
1806-
char* buf,
1807-
size_t bufsize,
1808-
size_t* result)
1805+
napi_status napi_get_value_string_latin1(napi_env env,
1806+
napi_value value,
1807+
char* buf,
1808+
size_t bufsize,
1809+
size_t* result)
18091810
```
18101811

18111812
- `[in] env`: The environment that the API is invoked under.
@@ -2780,8 +2781,8 @@ in as arguments to the function.
27802781
Returns `napi_ok` if the API succeeded.
27812782

27822783
This method allows a JavaScript function object to be called from a native
2783-
add-on. This is an primary mechanism of calling back *from* the add-on's
2784-
native code *into* JavaScript. For special cases like calling into JavaScript
2784+
add-on. This is the primary mechanism of calling back *from* the add-on's
2785+
native code *into* JavaScript. For the special case of calling into JavaScript
27852786
after an async operation, see [`napi_make_callback`][].
27862787

27872788
A sample use case might look as follows. Consider the following JavaScript
@@ -2993,39 +2994,6 @@ status = napi_new_instance(env, constructor, argc, argv, &value);
29932994

29942995
Returns `napi_ok` if the API succeeded.
29952996

2996-
### *napi_make_callback*
2997-
<!-- YAML
2998-
added: v8.0.0
2999-
-->
3000-
```C
3001-
napi_status napi_make_callback(napi_env env,
3002-
napi_value recv,
3003-
napi_value func,
3004-
int argc,
3005-
const napi_value* argv,
3006-
napi_value* result)
3007-
```
3008-
3009-
- `[in] env`: The environment that the API is invoked under.
3010-
- `[in] recv`: The `this` object passed to the called function.
3011-
- `[in] func`: `napi_value` representing the JavaScript function
3012-
to be invoked.
3013-
- `[in] argc`: The count of elements in the `argv` array.
3014-
- `[in] argv`: Array of JavaScript values as `napi_value`
3015-
representing the arguments to the function.
3016-
- `[out] result`: `napi_value` representing the JavaScript object returned.
3017-
3018-
Returns `napi_ok` if the API succeeded.
3019-
3020-
This method allows a JavaScript function object to be called from a native
3021-
add-on. This API is similar to `napi_call_function`. However, it is used to call
3022-
*from* native code back *into* JavaScript *after* returning from an async
3023-
operation (when there is no other script on the stack). It is a fairly simple
3024-
wrapper around `node::MakeCallback`.
3025-
3026-
For an example on how to use `napi_make_callback`, see the section on
3027-
[Asynchronous Operations][].
3028-
30292997
## Object Wrap
30302998

30312999
N-API offers a way to "wrap" C++ classes and instances so that the class
@@ -3204,7 +3172,7 @@ restoring the JavaScript object's prototype chain. If a finalize callback was
32043172
associated with the wrapping, it will no longer be called when the JavaScript
32053173
object becomes garbage-collected.
32063174

3207-
## Asynchronous Operations
3175+
## Simple Asynchronous Operations
32083176

32093177
Addon modules often need to leverage async helpers from libuv as part of their
32103178
implementation. This allows them to schedule work to be executed asynchronously
@@ -3240,8 +3208,8 @@ Once created the async worker can be queued
32403208
for execution using the [`napi_queue_async_work`][] function:
32413209

32423210
```C
3243-
NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
3244-
napi_async_work work);
3211+
napi_status napi_queue_async_work(napi_env env,
3212+
napi_async_work work);
32453213
```
32463214

32473215
[`napi_cancel_async_work`][] can be used if the work needs
@@ -3257,7 +3225,6 @@ callback invocation, even when it was cancelled.
32573225
added: v8.0.0
32583226
-->
32593227
```C
3260-
NAPI_EXTERN
32613228
napi_status napi_create_async_work(napi_env env,
32623229
napi_async_execute_callback execute,
32633230
napi_async_complete_callback complete,
@@ -3286,8 +3253,8 @@ required.
32863253
added: v8.0.0
32873254
-->
32883255
```C
3289-
NAPI_EXTERN napi_status napi_delete_async_work(napi_env env,
3290-
napi_async_work work);
3256+
napi_status napi_delete_async_work(napi_env env,
3257+
napi_async_work work);
32913258
```
32923259

32933260
- `[in] env`: The environment that the API is invoked under.
@@ -3302,8 +3269,8 @@ This API frees a previously allocated work object.
33023269
added: v8.0.0
33033270
-->
33043271
```C
3305-
NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
3306-
napi_async_work work);
3272+
napi_status napi_queue_async_work(napi_env env,
3273+
napi_async_work work);
33073274
```
33083275

33093276
- `[in] env`: The environment that the API is invoked under.
@@ -3319,8 +3286,8 @@ for execution.
33193286
added: v8.0.0
33203287
-->
33213288
```C
3322-
NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env,
3323-
napi_async_work work);
3289+
napi_status napi_cancel_async_work(napi_env env,
3290+
napi_async_work work);
33243291
```
33253292

33263293
- `[in] env`: The environment that the API is invoked under.
@@ -3335,6 +3302,92 @@ the `complete` callback will be invoked with a status value of
33353302
`napi_cancelled`. The work should not be deleted before the `complete`
33363303
callback invocation, even if it has been successfully cancelled.
33373304

3305+
## Custom Asynchronous Operations
3306+
The simple asynchronous work APIs above may not be appropriate for every
3307+
scenario, because with those the async execution still happens on the main
3308+
event loop. When using any other async mechanism, the following APIs are
3309+
necessary to ensure an async operation is properly tracked by the runtime.
3310+
3311+
### *napi_async_init**
3312+
<!-- YAML
3313+
added: REPLACEME
3314+
-->
3315+
```C
3316+
napi_status napi_async_init(napi_env env,
3317+
napi_value async_resource,
3318+
const char* async_resource_name,
3319+
napi_async_context* result)
3320+
```
3321+
3322+
- `[in] env`: The environment that the API is invoked under.
3323+
- `[in] async_resource`: An optional object associated with the async work
3324+
that will be passed to possible async_hooks [`init` hooks][].
3325+
- `[in] async_resource_name`: An identifier for the kind of resource that is
3326+
being provided for diagnostic information exposed by the `async_hooks` API.
3327+
- `[out] result`: The initialized async context.
3328+
3329+
Returns `napi_ok` if the API succeeded.
3330+
3331+
### *napi_async_destroy**
3332+
<!-- YAML
3333+
added: REPLACEME
3334+
-->
3335+
```C
3336+
napi_status napi_async_destroy(napi_env env,
3337+
napi_async_context async_context);
3338+
```
3339+
3340+
- `[in] env`: The environment that the API is invoked under.
3341+
- `[in] async_context`: The async context to be destroyed.
3342+
3343+
Returns `napi_ok` if the API succeeded.
3344+
3345+
### *napi_make_callback*
3346+
<!-- YAML
3347+
added: v8.0.0
3348+
changes:
3349+
- version: REPLACEME
3350+
description: Added `async_context` parameter.
3351+
-->
3352+
```C
3353+
napi_status napi_make_callback(napi_env env,
3354+
napi_async_context async_context,
3355+
napi_value recv,
3356+
napi_value func,
3357+
int argc,
3358+
const napi_value* argv,
3359+
napi_value* result)
3360+
```
3361+
3362+
- `[in] env`: The environment that the API is invoked under.
3363+
- `[in] async_context`: Context for the async operation that is
3364+
invoking the callback. This should normally be a value previously
3365+
obtained from [`napi_async_init`][]. However `NULL` is also allowed,
3366+
which indicates the current async context (if any) is to be used
3367+
for the callback.
3368+
- `[in] recv`: The `this` object passed to the called function.
3369+
- `[in] func`: `napi_value` representing the JavaScript function
3370+
to be invoked.
3371+
- `[in] argc`: The count of elements in the `argv` array.
3372+
- `[in] argv`: Array of JavaScript values as `napi_value`
3373+
representing the arguments to the function.
3374+
- `[out] result`: `napi_value` representing the JavaScript object returned.
3375+
3376+
Returns `napi_ok` if the API succeeded.
3377+
3378+
This method allows a JavaScript function object to be called from a native
3379+
add-on. This API is similar to `napi_call_function`. However, it is used to call
3380+
*from* native code back *into* JavaScript *after* returning from an async
3381+
operation (when there is no other script on the stack). It is a fairly simple
3382+
wrapper around `node::MakeCallback`.
3383+
3384+
Note it is NOT necessary to use `napi_make_callback` from within a
3385+
`napi_async_complete_callback`; in that situation the callback's async
3386+
context has already been set up, so a direct call to `napi_call_function`
3387+
is sufficient and appropriate. Use of the `napi_make_callback` function
3388+
may be required when implementing custom async behavior that does not use
3389+
`napi_create_async_work`.
3390+
33383391
## Version Management
33393392

33403393
### napi_get_node_version
@@ -3350,7 +3403,6 @@ typedef struct {
33503403
const char* release;
33513404
} napi_node_version;
33523405

3353-
NAPI_EXTERN
33543406
napi_status napi_get_node_version(napi_env env,
33553407
const napi_node_version** version);
33563408
```
@@ -3371,8 +3423,8 @@ The returned buffer is statically allocated and does not need to be freed.
33713423
added: v8.0.0
33723424
-->
33733425
```C
3374-
NAPI_EXTERN napi_status napi_get_version(napi_env env,
3375-
uint32_t* result);
3426+
napi_status napi_get_version(napi_env env,
3427+
uint32_t* result);
33763428
```
33773429

33783430
- `[in] env`: The environment that the API is invoked under.
@@ -3455,9 +3507,9 @@ deferred = NULL;
34553507
added: REPLACEME
34563508
-->
34573509
```C
3458-
NAPI_EXTERN napi_status napi_create_promise(napi_env env,
3459-
napi_deferred* deferred,
3460-
napi_value* promise);
3510+
napi_status napi_create_promise(napi_env env,
3511+
napi_deferred* deferred,
3512+
napi_value* promise);
34613513
```
34623514

34633515
- `[in] env`: The environment that the API is invoked under.
@@ -3475,9 +3527,9 @@ This API creates a deferred object and a JavaScript promise.
34753527
added: REPLACEME
34763528
-->
34773529
```C
3478-
NAPI_EXTERN napi_status napi_resolve_deferred(napi_env env,
3479-
napi_deferred deferred,
3480-
napi_value resolution);
3530+
napi_status napi_resolve_deferred(napi_env env,
3531+
napi_deferred deferred,
3532+
napi_value resolution);
34813533
```
34823534

34833535
- `[in] env`: The environment that the API is invoked under.
@@ -3498,9 +3550,9 @@ The deferred object is freed upon successful completion.
34983550
added: REPLACEME
34993551
-->
35003552
```C
3501-
NAPI_EXTERN napi_status napi_reject_deferred(napi_env env,
3502-
napi_deferred deferred,
3503-
napi_value rejection);
3553+
napi_status napi_reject_deferred(napi_env env,
3554+
napi_deferred deferred,
3555+
napi_value rejection);
35043556
```
35053557

35063558
- `[in] env`: The environment that the API is invoked under.
@@ -3521,9 +3573,9 @@ The deferred object is freed upon successful completion.
35213573
added: REPLACEME
35223574
-->
35233575
```C
3524-
NAPI_EXTERN napi_status napi_is_promise(napi_env env,
3525-
napi_value promise,
3526-
bool* is_promise);
3576+
napi_status napi_is_promise(napi_env env,
3577+
napi_value promise,
3578+
bool* is_promise);
35273579
```
35283580

35293581
- `[in] env`: The environment that the API is invoked under.
@@ -3532,7 +3584,8 @@ NAPI_EXTERN napi_status napi_is_promise(napi_env env,
35323584
object - that is, a promise object created by the underlying engine.
35333585

35343586
[Promises]: #n_api_promises
3535-
[Asynchronous Operations]: #n_api_asynchronous_operations
3587+
[Simple Asynchronous Operations]: #n_api_asynchronous_operations
3588+
[Custom Asynchronous Operations]: #n_api_custom_asynchronous_operations
35363589
[Basic N-API Data Types]: #n_api_basic_n_api_data_types
35373590
[ECMAScript Language Specification]: https://tc39.github.io/ecma262/
35383591
[Error Handling]: #n_api_error_handling

0 commit comments

Comments
 (0)