Skip to content

Commit 87a3162

Browse files
jasonginjasnell
authored andcommitted
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. PR-URL: #15189 Fixes: #13254 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 7b7c030 commit 87a3162

File tree

7 files changed

+259
-96
lines changed

7 files changed

+259
-96
lines changed

doc/api/n-api.md

Lines changed: 134 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
* [Script Execution][]
4748

@@ -264,7 +265,7 @@ It is intended only for logging purposes.
264265
added: v8.0.0
265266
-->
266267
```C
267-
NAPI_EXTERN napi_status
268+
napi_status
268269
napi_get_last_error_info(napi_env env,
269270
const napi_extended_error_info** result);
270271
```
@@ -515,8 +516,8 @@ This API returns a JavaScript RangeError with the text provided.
515516
added: v8.0.0
516517
-->
517518
```C
518-
NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env,
519-
napi_value* result);
519+
napi_status napi_get_and_clear_last_exception(napi_env env,
520+
napi_value* result);
520521
```
521522

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

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

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

727728
- `[in] env`: The environment that the API is invoked under.
@@ -1478,10 +1479,10 @@ of the ECMAScript Language Specification.
14781479
added: v8.0.0
14791480
-->
14801481
```C
1481-
NAPI_EXTERN napi_status napi_create_string_latin1(napi_env env,
1482-
const char* str,
1483-
size_t length,
1484-
napi_value* result);
1482+
napi_status napi_create_string_latin1(napi_env env,
1483+
const char* str,
1484+
size_t length,
1485+
napi_value* result);
14851486
```
14861487

14871488
- `[in] env`: The environment that the API is invoked under.
@@ -1811,11 +1812,11 @@ JavaScript Number
18111812
added: v8.0.0
18121813
-->
18131814
```C
1814-
NAPI_EXTERN napi_status napi_get_value_string_latin1(napi_env env,
1815-
napi_value value,
1816-
char* buf,
1817-
size_t bufsize,
1818-
size_t* result)
1815+
napi_status napi_get_value_string_latin1(napi_env env,
1816+
napi_value value,
1817+
char* buf,
1818+
size_t bufsize,
1819+
size_t* result)
18191820
```
18201821

18211822
- `[in] env`: The environment that the API is invoked under.
@@ -2790,8 +2791,8 @@ in as arguments to the function.
27902791
Returns `napi_ok` if the API succeeded.
27912792

27922793
This method allows a JavaScript function object to be called from a native
2793-
add-on. This is an primary mechanism of calling back *from* the add-on's
2794-
native code *into* JavaScript. For special cases like calling into JavaScript
2794+
add-on. This is the primary mechanism of calling back *from* the add-on's
2795+
native code *into* JavaScript. For the special case of calling into JavaScript
27952796
after an async operation, see [`napi_make_callback`][].
27962797

27972798
A sample use case might look as follows. Consider the following JavaScript
@@ -3002,39 +3003,6 @@ status = napi_new_instance(env, constructor, argc, argv, &value);
30023003

30033004
Returns `napi_ok` if the API succeeded.
30043005

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

30403008
N-API offers a way to "wrap" C++ classes and instances so that the class
@@ -3213,7 +3181,7 @@ restoring the JavaScript object's prototype chain. If a finalize callback was
32133181
associated with the wrapping, it will no longer be called when the JavaScript
32143182
object becomes garbage-collected.
32153183

3216-
## Asynchronous Operations
3184+
## Simple Asynchronous Operations
32173185

32183186
Addon modules often need to leverage async helpers from libuv as part of their
32193187
implementation. This allows them to schedule work to be executed asynchronously
@@ -3249,8 +3217,8 @@ Once created the async worker can be queued
32493217
for execution using the [`napi_queue_async_work`][] function:
32503218

32513219
```C
3252-
NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
3253-
napi_async_work work);
3220+
napi_status napi_queue_async_work(napi_env env,
3221+
napi_async_work work);
32543222
```
32553223

32563224
[`napi_cancel_async_work`][] can be used if the work needs
@@ -3270,7 +3238,6 @@ changes:
32703238
description: Added `async_resource` and `async_resource_name` parameters.
32713239
-->
32723240
```C
3273-
NAPI_EXTERN
32743241
napi_status napi_create_async_work(napi_env env,
32753242
napi_value async_resource,
32763243
napi_value async_resource_name,
@@ -3313,8 +3280,8 @@ for more information.
33133280
added: v8.0.0
33143281
-->
33153282
```C
3316-
NAPI_EXTERN napi_status napi_delete_async_work(napi_env env,
3317-
napi_async_work work);
3283+
napi_status napi_delete_async_work(napi_env env,
3284+
napi_async_work work);
33183285
```
33193286

33203287
- `[in] env`: The environment that the API is invoked under.
@@ -3329,8 +3296,8 @@ This API frees a previously allocated work object.
33293296
added: v8.0.0
33303297
-->
33313298
```C
3332-
NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
3333-
napi_async_work work);
3299+
napi_status napi_queue_async_work(napi_env env,
3300+
napi_async_work work);
33343301
```
33353302

33363303
- `[in] env`: The environment that the API is invoked under.
@@ -3346,8 +3313,8 @@ for execution.
33463313
added: v8.0.0
33473314
-->
33483315
```C
3349-
NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env,
3350-
napi_async_work work);
3316+
napi_status napi_cancel_async_work(napi_env env,
3317+
napi_async_work work);
33513318
```
33523319

33533320
- `[in] env`: The environment that the API is invoked under.
@@ -3362,6 +3329,93 @@ the `complete` callback will be invoked with a status value of
33623329
`napi_cancelled`. The work should not be deleted before the `complete`
33633330
callback invocation, even if it has been successfully cancelled.
33643331

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

33673421
### napi_get_node_version
@@ -3377,7 +3431,6 @@ typedef struct {
33773431
const char* release;
33783432
} napi_node_version;
33793433

3380-
NAPI_EXTERN
33813434
napi_status napi_get_node_version(napi_env env,
33823435
const napi_node_version** version);
33833436
```
@@ -3398,8 +3451,8 @@ The returned buffer is statically allocated and does not need to be freed.
33983451
added: v8.0.0
33993452
-->
34003453
```C
3401-
NAPI_EXTERN napi_status napi_get_version(napi_env env,
3402-
uint32_t* result);
3454+
napi_status napi_get_version(napi_env env,
3455+
uint32_t* result);
34033456
```
34043457

34053458
- `[in] env`: The environment that the API is invoked under.
@@ -3507,9 +3560,9 @@ deferred = NULL;
35073560
added: v8.5.0
35083561
-->
35093562
```C
3510-
NAPI_EXTERN napi_status napi_create_promise(napi_env env,
3511-
napi_deferred* deferred,
3512-
napi_value* promise);
3563+
napi_status napi_create_promise(napi_env env,
3564+
napi_deferred* deferred,
3565+
napi_value* promise);
35133566
```
35143567

35153568
- `[in] env`: The environment that the API is invoked under.
@@ -3527,9 +3580,9 @@ This API creates a deferred object and a JavaScript promise.
35273580
added: v8.5.0
35283581
-->
35293582
```C
3530-
NAPI_EXTERN napi_status napi_resolve_deferred(napi_env env,
3531-
napi_deferred deferred,
3532-
napi_value resolution);
3583+
napi_status napi_resolve_deferred(napi_env env,
3584+
napi_deferred deferred,
3585+
napi_value resolution);
35333586
```
35343587

35353588
- `[in] env`: The environment that the API is invoked under.
@@ -3550,9 +3603,9 @@ The deferred object is freed upon successful completion.
35503603
added: v8.5.0
35513604
-->
35523605
```C
3553-
NAPI_EXTERN napi_status napi_reject_deferred(napi_env env,
3554-
napi_deferred deferred,
3555-
napi_value rejection);
3606+
napi_status napi_reject_deferred(napi_env env,
3607+
napi_deferred deferred,
3608+
napi_value rejection);
35563609
```
35573610

35583611
- `[in] env`: The environment that the API is invoked under.
@@ -3573,9 +3626,9 @@ The deferred object is freed upon successful completion.
35733626
added: v8.5.0
35743627
-->
35753628
```C
3576-
NAPI_EXTERN napi_status napi_is_promise(napi_env env,
3577-
napi_value promise,
3578-
bool* is_promise);
3629+
napi_status napi_is_promise(napi_env env,
3630+
napi_value promise,
3631+
bool* is_promise);
35793632
```
35803633

35813634
- `[in] env`: The environment that the API is invoked under.
@@ -3603,7 +3656,8 @@ NAPI_EXTERN napi_status napi_run_script(napi_env env,
36033656
- `[out] result`: The value resulting from having executed the script.
36043657

36053658
[Promises]: #n_api_promises
3606-
[Asynchronous Operations]: #n_api_asynchronous_operations
3659+
[Simple Asynchronous Operations]: #n_api_asynchronous_operations
3660+
[Custom Asynchronous Operations]: #n_api_custom_asynchronous_operations
36073661
[Basic N-API Data Types]: #n_api_basic_n_api_data_types
36083662
[ECMAScript Language Specification]: https://tc39.github.io/ecma262/
36093663
[Error Handling]: #n_api_error_handling

0 commit comments

Comments
 (0)