mirror of https://github.com/lukechilds/node.git
Browse Source
Promise is implemented as a pair of objects. `napi_create_promise()` returns both a JavaScript promise and a newly allocated "deferred" in its out-params. The deferred is linked to the promise such that the deferred can be passed to `napi_resolve_deferred()` or `napi_reject_deferred()` to reject/resolve the promise. `napi_is_promise()` can be used to check if a `napi_value` is a native promise - that is, a promise created by the underlying engine, rather than a pure JS implementation of a promise. PR-URL: https://github.com/nodejs/node/pull/14365 Fixes: https://github.com/nodejs/abi-stable-node/issues/242 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com>canary-base
7 changed files with 359 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_promise", |
|||
"sources": [ "test_promise.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,60 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../../common'); |
|||
const test_promise = require(`./build/${common.buildType}/test_promise`); |
|||
const assert = require('assert'); |
|||
|
|||
let expected_result, promise; |
|||
|
|||
// A resolution
|
|||
expected_result = 42; |
|||
promise = test_promise.createPromise(); |
|||
promise.then( |
|||
common.mustCall(function(result) { |
|||
assert.strictEqual(result, expected_result, |
|||
'promise resolved as expected'); |
|||
}), |
|||
common.mustNotCall()); |
|||
test_promise.concludeCurrentPromise(expected_result, true); |
|||
|
|||
// A rejection
|
|||
expected_result = 'It\'s not you, it\'s me.'; |
|||
promise = test_promise.createPromise(); |
|||
promise.then( |
|||
common.mustNotCall(), |
|||
common.mustCall(function(result) { |
|||
assert.strictEqual(result, expected_result, |
|||
'promise rejected as expected'); |
|||
})); |
|||
test_promise.concludeCurrentPromise(expected_result, false); |
|||
|
|||
// Chaining
|
|||
promise = test_promise.createPromise(); |
|||
promise.then( |
|||
common.mustCall(function(result) { |
|||
assert.strictEqual(result, 'chained answer', |
|||
'resolving with a promise chains properly'); |
|||
}), |
|||
common.mustNotCall()); |
|||
test_promise.concludeCurrentPromise(Promise.resolve('chained answer'), true); |
|||
|
|||
assert.strictEqual(test_promise.isPromise(promise), true, |
|||
'natively created promise is recognized as a promise'); |
|||
|
|||
assert.strictEqual(test_promise.isPromise(Promise.reject(-1)), true, |
|||
'Promise created with JS is recognized as a promise'); |
|||
|
|||
assert.strictEqual(test_promise.isPromise(2.4), false, |
|||
'Number is recognized as not a promise'); |
|||
|
|||
assert.strictEqual(test_promise.isPromise('I promise!'), false, |
|||
'String is recognized as not a promise'); |
|||
|
|||
assert.strictEqual(test_promise.isPromise(undefined), false, |
|||
'undefined is recognized as not a promise'); |
|||
|
|||
assert.strictEqual(test_promise.isPromise(null), false, |
|||
'null is recognized as not a promise'); |
|||
|
|||
assert.strictEqual(test_promise.isPromise({}), false, |
|||
'an object is recognized as not a promise'); |
@ -0,0 +1,60 @@ |
|||
#include <node_api.h> |
|||
#include "../common.h" |
|||
|
|||
napi_deferred deferred = NULL; |
|||
|
|||
napi_value createPromise(napi_env env, napi_callback_info info) { |
|||
napi_value promise; |
|||
|
|||
// We do not overwrite an existing deferred.
|
|||
if (deferred != NULL) { |
|||
return NULL; |
|||
} |
|||
|
|||
NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); |
|||
|
|||
return promise; |
|||
} |
|||
|
|||
napi_value concludeCurrentPromise(napi_env env, napi_callback_info info) { |
|||
napi_value argv[2]; |
|||
size_t argc = 2; |
|||
bool resolution; |
|||
|
|||
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); |
|||
NAPI_CALL(env, napi_get_value_bool(env, argv[1], &resolution)); |
|||
if (resolution) { |
|||
NAPI_CALL(env, napi_resolve_deferred(env, deferred, argv[0])); |
|||
} else { |
|||
NAPI_CALL(env, napi_reject_deferred(env, deferred, argv[0])); |
|||
} |
|||
|
|||
deferred = NULL; |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
napi_value isPromise(napi_env env, napi_callback_info info) { |
|||
napi_value promise, result; |
|||
size_t argc = 1; |
|||
bool is_promise; |
|||
|
|||
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &promise, NULL, NULL)); |
|||
NAPI_CALL(env, napi_is_promise(env, promise, &is_promise)); |
|||
NAPI_CALL(env, napi_get_boolean(env, is_promise, &result)); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_PROPERTY("createPromise", createPromise), |
|||
DECLARE_NAPI_PROPERTY("concludeCurrentPromise", concludeCurrentPromise), |
|||
DECLARE_NAPI_PROPERTY("isPromise", isPromise), |
|||
}; |
|||
|
|||
NAPI_CALL_RETURN_VOID(env, napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
Loading…
Reference in new issue