Permalink
Browse files

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: #12442
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: William Kapke <william.kapke@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
  • Loading branch information...
addaleax committed Apr 14, 2017
1 parent f72376d commit 059f2960503eec1418c32226646f5a2af6ae85f0
Showing with 76 additions and 0 deletions.
  1. +35 −0 src/node_util.cc
  2. +41 −0 test/parallel/test-promise-internal-creation.js
View
@@ -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<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) {
@@ -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
@@ -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.