mirror of https://github.com/lukechilds/node.git
Browse Source
Based on the async methods we had in abi-stable-node before the napi feature landed in node/master. Changed this set of APIs to handle error cases and removed a lot of the extra methods we had for setting all the pieces of napi_work opting instead to pass all of those as arguments to napi_create_async_work as none of those parameters are optional except for the complete callback, anyway. Renamed the napi_work struct to napi_async_work and replace the struct itself with a class which can better encapsulate the object lifetime and uv_work_t that we're trying to wrap anyway. Added a napi_async_callback type for the async helper callbacks instead of taking raw function pointers and make this callback take a napi_env parameter as well as the void* data it was already taking. Call the complete handler for the async work item with a napi_status code translated from the uvlib error code. The execute callback is required for napi_create_async_work, though complete callback is still optional. Also added some async unit tests for addons-napi based on the addons/async_hello_world test. PR-URL: https://github.com/nodejs/node/pull/12250 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com> Reviewed-By: Hitesh Kanwathirtha <hiteshk@microsoft.com>v6
committed by
Anna Henningsen
6 changed files with 318 additions and 21 deletions
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_async", |
|||
"sources": [ "test_async.cc" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,10 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const test_async = require(`./build/${common.buildType}/test_async`); |
|||
|
|||
test_async(5, common.mustCall(function(err, val) { |
|||
assert.strictEqual(err, null); |
|||
assert.strictEqual(val, 10); |
|||
process.nextTick(common.mustCall(function() {})); |
|||
})); |
@ -0,0 +1,122 @@ |
|||
#include <node_api.h> |
|||
#include "../common.h" |
|||
|
|||
#if defined _WIN32 |
|||
#include <windows.h> |
|||
#else |
|||
#include <unistd.h> |
|||
#endif |
|||
|
|||
typedef struct { |
|||
int32_t _input; |
|||
int32_t _output; |
|||
napi_ref _callback; |
|||
napi_async_work _request; |
|||
} carrier; |
|||
|
|||
carrier the_carrier; |
|||
|
|||
struct AutoHandleScope { |
|||
explicit AutoHandleScope(napi_env env) |
|||
: _env(env), |
|||
_scope(nullptr) { |
|||
napi_open_handle_scope(_env, &_scope); |
|||
} |
|||
~AutoHandleScope() { |
|||
napi_close_handle_scope(_env, _scope); |
|||
} |
|||
private: |
|||
AutoHandleScope() { } |
|||
|
|||
napi_env _env; |
|||
napi_handle_scope _scope; |
|||
}; |
|||
|
|||
void Execute(napi_env env, void* data) { |
|||
#if defined _WIN32 |
|||
Sleep(1000); |
|||
#else |
|||
sleep(1); |
|||
#endif |
|||
carrier* c = static_cast<carrier*>(data); |
|||
|
|||
if (c != &the_carrier) { |
|||
napi_throw_type_error(env, "Wrong data parameter to Execute."); |
|||
return; |
|||
} |
|||
|
|||
c->_output = c->_input * 2; |
|||
} |
|||
|
|||
void Complete(napi_env env, napi_status status, void* data) { |
|||
AutoHandleScope scope(env); |
|||
carrier* c = static_cast<carrier*>(data); |
|||
|
|||
if (c != &the_carrier) { |
|||
napi_throw_type_error(env, "Wrong data parameter to Complete."); |
|||
return; |
|||
} |
|||
|
|||
if (status != napi_ok) { |
|||
napi_throw_type_error(env, "Execute callback failed."); |
|||
return; |
|||
} |
|||
|
|||
napi_value argv[2]; |
|||
|
|||
NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &argv[0])); |
|||
NAPI_CALL_RETURN_VOID(env, napi_create_number(env, c->_output, &argv[1])); |
|||
napi_value callback; |
|||
NAPI_CALL_RETURN_VOID(env, |
|||
napi_get_reference_value(env, c->_callback, &callback)); |
|||
napi_value global; |
|||
NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global)); |
|||
|
|||
napi_value result; |
|||
NAPI_CALL_RETURN_VOID(env, |
|||
napi_call_function(env, global, callback, 2, argv, &result)); |
|||
|
|||
NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback)); |
|||
NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request)); |
|||
} |
|||
|
|||
napi_value Test(napi_env env, napi_callback_info info) { |
|||
size_t argc = 2; |
|||
napi_value argv[2]; |
|||
napi_value _this; |
|||
void* data; |
|||
NAPI_CALL(env, |
|||
napi_get_cb_info(env, info, &argc, argv, &_this, &data)); |
|||
NAPI_ASSERT(env, argc >= 2, "Not enough arguments, expected 2."); |
|||
|
|||
napi_valuetype t; |
|||
NAPI_CALL(env, napi_typeof(env, argv[0], &t)); |
|||
NAPI_ASSERT(env, t == napi_number, |
|||
"Wrong first argument, integer expected."); |
|||
NAPI_CALL(env, napi_typeof(env, argv[1], &t)); |
|||
NAPI_ASSERT(env, t == napi_function, |
|||
"Wrong second argument, function expected."); |
|||
|
|||
the_carrier._output = 0; |
|||
|
|||
NAPI_CALL(env, |
|||
napi_get_value_int32(env, argv[0], &the_carrier._input)); |
|||
NAPI_CALL(env, |
|||
napi_create_reference(env, argv[1], 1, &the_carrier._callback)); |
|||
NAPI_CALL(env, napi_create_async_work( |
|||
env, Execute, Complete, &the_carrier, &the_carrier._request)); |
|||
NAPI_CALL(env, |
|||
napi_queue_async_work(env, the_carrier._request)); |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_value test; |
|||
NAPI_CALL_RETURN_VOID(env, |
|||
napi_create_function(env, "Test", Test, nullptr, &test)); |
|||
NAPI_CALL_RETURN_VOID(env, |
|||
napi_set_named_property(env, module, "exports", test)); |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
Loading…
Reference in new issue