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