From 059f2960503eec1418c32226646f5a2af6ae85f0 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 14 Apr 2017 18:27:46 +0200 Subject: [PATCH] util: add internal bindings for promise handling Add methods for creating, resolving and rejecting promises using the V8 C++ API that does not require creation of extra `resolve` and `reject` functions to `process.binding('util')`. PR-URL: https://github.com/nodejs/node/pull/12442 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Myles Borins Reviewed-By: Evan Lucas Reviewed-By: William Kapke Reviewed-By: Timothy Gu Reviewed-By: Teddy Katz --- src/node_util.cc | 35 ++++++++++++++++ .../test-promise-internal-creation.js | 41 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 test/parallel/test-promise-internal-creation.js diff --git a/src/node_util.cc b/src/node_util.cc index 5f3de643d4c2f3..3424739cc96688 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -12,6 +12,7 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Integer; using v8::Local; +using v8::Maybe; using v8::Object; using v8::Private; using v8::Promise; @@ -147,6 +148,36 @@ void WatchdogHasPendingSigint(const FunctionCallbackInfo& args) { } +void CreatePromise(const FunctionCallbackInfo& args) { + Local context = args.GetIsolate()->GetCurrentContext(); + auto maybe_resolver = Promise::Resolver::New(context); + if (!maybe_resolver.IsEmpty()) + args.GetReturnValue().Set(maybe_resolver.ToLocalChecked()); +} + + +void PromiseResolve(const FunctionCallbackInfo& args) { + Local context = args.GetIsolate()->GetCurrentContext(); + Local promise = args[0]; + CHECK(promise->IsPromise()); + if (promise.As()->State() != Promise::kPending) return; + Local resolver = promise.As(); // sic + Maybe ret = resolver->Resolve(context, args[1]); + args.GetReturnValue().Set(ret.FromMaybe(false)); +} + + +void PromiseReject(const FunctionCallbackInfo& args) { + Local context = args.GetIsolate()->GetCurrentContext(); + Local promise = args[0]; + CHECK(promise->IsPromise()); + if (promise.As()->State() != Promise::kPending) return; + Local resolver = promise.As(); // sic + Maybe ret = resolver->Reject(context, args[1]); + args.GetReturnValue().Set(ret.FromMaybe(false)); +} + + void Initialize(Local target, Local unused, Local context) { @@ -192,6 +223,10 @@ void Initialize(Local target, env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog); env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog); env->SetMethod(target, "watchdogHasPendingSigint", WatchdogHasPendingSigint); + + env->SetMethod(target, "createPromise", CreatePromise); + env->SetMethod(target, "promiseResolve", PromiseResolve); + env->SetMethod(target, "promiseReject", PromiseReject); } } // namespace util diff --git a/test/parallel/test-promise-internal-creation.js b/test/parallel/test-promise-internal-creation.js new file mode 100644 index 00000000000000..7142c872d9452e --- /dev/null +++ b/test/parallel/test-promise-internal-creation.js @@ -0,0 +1,41 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { + createPromise, promiseResolve, promiseReject +} = process.binding('util'); +const { inspect } = require('util'); + +common.crashOnUnhandledRejection(); + +{ + const promise = createPromise(); + assert.strictEqual(inspect(promise), 'Promise { }'); + promiseResolve(promise, 42); + assert.strictEqual(inspect(promise), 'Promise { 42 }'); + promise.then(common.mustCall((value) => { + assert.strictEqual(value, 42); + })); +} + +{ + const promise = createPromise(); + const error = new Error('foobar'); + promiseReject(promise, error); + assert(inspect(promise).includes(' Error: foobar')); + promise.catch(common.mustCall((value) => { + assert.strictEqual(value, error); + })); +} + +{ + const promise = createPromise(); + const error = new Error('foobar'); + promiseReject(promise, error); + assert(inspect(promise).includes(' Error: foobar')); + promiseResolve(promise, 42); + assert(inspect(promise).includes(' Error: foobar')); + promise.catch(common.mustCall((value) => { + assert.strictEqual(value, error); + })); +}