Skip to content

Commit

Permalink
util: add internal bindings for promise handling
Browse files Browse the repository at this point in the history
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: nodejs#12442
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Myles Borins <[email protected]>
Reviewed-By: Evan Lucas <[email protected]>
Reviewed-By: William Kapke <[email protected]>
Reviewed-By: Timothy Gu <[email protected]>
Reviewed-By: Teddy Katz <[email protected]>
  • Loading branch information
addaleax committed May 9, 2017
1 parent f72376d commit 059f296
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/node_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -147,6 +148,36 @@ void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
}


void CreatePromise(const FunctionCallbackInfo<Value>& args) {
Local<Context> 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<Value>& args) {
Local<Context> context = args.GetIsolate()->GetCurrentContext();
Local<Value> promise = args[0];
CHECK(promise->IsPromise());
if (promise.As<Promise>()->State() != Promise::kPending) return;
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>(); // sic
Maybe<bool> ret = resolver->Resolve(context, args[1]);
args.GetReturnValue().Set(ret.FromMaybe(false));
}


void PromiseReject(const FunctionCallbackInfo<Value>& args) {
Local<Context> context = args.GetIsolate()->GetCurrentContext();
Local<Value> promise = args[0];
CHECK(promise->IsPromise());
if (promise.As<Promise>()->State() != Promise::kPending) return;
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>(); // sic
Maybe<bool> ret = resolver->Reject(context, args[1]);
args.GetReturnValue().Set(ret.FromMaybe(false));
}


void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Expand Down Expand Up @@ -192,6 +223,10 @@ void Initialize(Local<Object> 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
Expand Down
41 changes: 41 additions & 0 deletions test/parallel/test-promise-internal-creation.js
Original file line number Diff line number Diff line change
@@ -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 { <pending> }');
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('<rejected> 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('<rejected> Error: foobar'));
promiseResolve(promise, 42);
assert(inspect(promise).includes('<rejected> Error: foobar'));
promise.catch(common.mustCall((value) => {
assert.strictEqual(value, error);
}));
}

0 comments on commit 059f296

Please sign in to comment.