Skip to content

Commit 0c258bd

Browse files
jasonginmhdawson
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 92e5f5c commit 0c258bd

File tree

7 files changed

+259
-96
lines changed

7 files changed

+259
-96
lines changed

doc/api/n-api.md

+134-80
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
@@ -3003,39 +3004,6 @@ status = napi_new_instance(env, constructor, argc, argv, &value);
30033004

30043005
Returns `napi_ok` if the API succeeded.
30053006

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

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

3217-
## Asynchronous Operations
3185+
## Simple Asynchronous Operations
32183186

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

32523220
```C
3253-
NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
3254-
napi_async_work work);
3221+
napi_status napi_queue_async_work(napi_env env,
3222+
napi_async_work work);
32553223
```
32563224

32573225
[`napi_cancel_async_work`][] can be used if the work needs
@@ -3271,7 +3239,6 @@ changes:
32713239
description: Added `async_resource` and `async_resource_name` parameters.
32723240
-->
32733241
```C
3274-
NAPI_EXTERN
32753242
napi_status napi_create_async_work(napi_env env,
32763243
napi_value async_resource,
32773244
napi_value async_resource_name,
@@ -3314,8 +3281,8 @@ for more information.
33143281
added: v8.0.0
33153282
-->
33163283
```C
3317-
NAPI_EXTERN napi_status napi_delete_async_work(napi_env env,
3318-
napi_async_work work);
3284+
napi_status napi_delete_async_work(napi_env env,
3285+
napi_async_work work);
33193286
```
33203287

33213288
- `[in] env`: The environment that the API is invoked under.
@@ -3330,8 +3297,8 @@ This API frees a previously allocated work object.
33303297
added: v8.0.0
33313298
-->
33323299
```C
3333-
NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
3334-
napi_async_work work);
3300+
napi_status napi_queue_async_work(napi_env env,
3301+
napi_async_work work);
33353302
```
33363303

33373304
- `[in] env`: The environment that the API is invoked under.
@@ -3347,8 +3314,8 @@ for execution.
33473314
added: v8.0.0
33483315
-->
33493316
```C
3350-
NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env,
3351-
napi_async_work work);
3317+
napi_status napi_cancel_async_work(napi_env env,
3318+
napi_async_work work);
33523319
```
33533320

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

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

33683422
### napi_get_node_version
@@ -3378,7 +3432,6 @@ typedef struct {
33783432
const char* release;
33793433
} napi_node_version;
33803434

3381-
NAPI_EXTERN
33823435
napi_status napi_get_node_version(napi_env env,
33833436
const napi_node_version** version);
33843437
```
@@ -3399,8 +3452,8 @@ The returned buffer is statically allocated and does not need to be freed.
33993452
added: v8.0.0
34003453
-->
34013454
```C
3402-
NAPI_EXTERN napi_status napi_get_version(napi_env env,
3403-
uint32_t* result);
3455+
napi_status napi_get_version(napi_env env,
3456+
uint32_t* result);
34043457
```
34053458

34063459
- `[in] env`: The environment that the API is invoked under.
@@ -3508,9 +3561,9 @@ deferred = NULL;
35083561
added: v8.5.0
35093562
-->
35103563
```C
3511-
NAPI_EXTERN napi_status napi_create_promise(napi_env env,
3512-
napi_deferred* deferred,
3513-
napi_value* promise);
3564+
napi_status napi_create_promise(napi_env env,
3565+
napi_deferred* deferred,
3566+
napi_value* promise);
35143567
```
35153568

35163569
- `[in] env`: The environment that the API is invoked under.
@@ -3528,9 +3581,9 @@ This API creates a deferred object and a JavaScript promise.
35283581
added: v8.5.0
35293582
-->
35303583
```C
3531-
NAPI_EXTERN napi_status napi_resolve_deferred(napi_env env,
3532-
napi_deferred deferred,
3533-
napi_value resolution);
3584+
napi_status napi_resolve_deferred(napi_env env,
3585+
napi_deferred deferred,
3586+
napi_value resolution);
35343587
```
35353588

35363589
- `[in] env`: The environment that the API is invoked under.
@@ -3551,9 +3604,9 @@ The deferred object is freed upon successful completion.
35513604
added: v8.5.0
35523605
-->
35533606
```C
3554-
NAPI_EXTERN napi_status napi_reject_deferred(napi_env env,
3555-
napi_deferred deferred,
3556-
napi_value rejection);
3607+
napi_status napi_reject_deferred(napi_env env,
3608+
napi_deferred deferred,
3609+
napi_value rejection);
35573610
```
35583611

35593612
- `[in] env`: The environment that the API is invoked under.
@@ -3574,9 +3627,9 @@ The deferred object is freed upon successful completion.
35743627
added: v8.5.0
35753628
-->
35763629
```C
3577-
NAPI_EXTERN napi_status napi_is_promise(napi_env env,
3578-
napi_value promise,
3579-
bool* is_promise);
3630+
napi_status napi_is_promise(napi_env env,
3631+
napi_value promise,
3632+
bool* is_promise);
35803633
```
35813634

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

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

0 commit comments

Comments
 (0)