Skip to content

Commit 059f296

Browse files
committed
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 <[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]>
1 parent f72376d commit 059f296

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/node_util.cc

+35
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ using v8::Context;
1212
using v8::FunctionCallbackInfo;
1313
using v8::Integer;
1414
using v8::Local;
15+
using v8::Maybe;
1516
using v8::Object;
1617
using v8::Private;
1718
using v8::Promise;
@@ -147,6 +148,36 @@ void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
147148
}
148149

149150

151+
void CreatePromise(const FunctionCallbackInfo<Value>& args) {
152+
Local<Context> context = args.GetIsolate()->GetCurrentContext();
153+
auto maybe_resolver = Promise::Resolver::New(context);
154+
if (!maybe_resolver.IsEmpty())
155+
args.GetReturnValue().Set(maybe_resolver.ToLocalChecked());
156+
}
157+
158+
159+
void PromiseResolve(const FunctionCallbackInfo<Value>& args) {
160+
Local<Context> context = args.GetIsolate()->GetCurrentContext();
161+
Local<Value> promise = args[0];
162+
CHECK(promise->IsPromise());
163+
if (promise.As<Promise>()->State() != Promise::kPending) return;
164+
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>(); // sic
165+
Maybe<bool> ret = resolver->Resolve(context, args[1]);
166+
args.GetReturnValue().Set(ret.FromMaybe(false));
167+
}
168+
169+
170+
void PromiseReject(const FunctionCallbackInfo<Value>& args) {
171+
Local<Context> context = args.GetIsolate()->GetCurrentContext();
172+
Local<Value> promise = args[0];
173+
CHECK(promise->IsPromise());
174+
if (promise.As<Promise>()->State() != Promise::kPending) return;
175+
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>(); // sic
176+
Maybe<bool> ret = resolver->Reject(context, args[1]);
177+
args.GetReturnValue().Set(ret.FromMaybe(false));
178+
}
179+
180+
150181
void Initialize(Local<Object> target,
151182
Local<Value> unused,
152183
Local<Context> context) {
@@ -192,6 +223,10 @@ void Initialize(Local<Object> target,
192223
env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
193224
env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
194225
env->SetMethod(target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
226+
227+
env->SetMethod(target, "createPromise", CreatePromise);
228+
env->SetMethod(target, "promiseResolve", PromiseResolve);
229+
env->SetMethod(target, "promiseReject", PromiseReject);
195230
}
196231

197232
} // namespace util
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const {
5+
createPromise, promiseResolve, promiseReject
6+
} = process.binding('util');
7+
const { inspect } = require('util');
8+
9+
common.crashOnUnhandledRejection();
10+
11+
{
12+
const promise = createPromise();
13+
assert.strictEqual(inspect(promise), 'Promise { <pending> }');
14+
promiseResolve(promise, 42);
15+
assert.strictEqual(inspect(promise), 'Promise { 42 }');
16+
promise.then(common.mustCall((value) => {
17+
assert.strictEqual(value, 42);
18+
}));
19+
}
20+
21+
{
22+
const promise = createPromise();
23+
const error = new Error('foobar');
24+
promiseReject(promise, error);
25+
assert(inspect(promise).includes('<rejected> Error: foobar'));
26+
promise.catch(common.mustCall((value) => {
27+
assert.strictEqual(value, error);
28+
}));
29+
}
30+
31+
{
32+
const promise = createPromise();
33+
const error = new Error('foobar');
34+
promiseReject(promise, error);
35+
assert(inspect(promise).includes('<rejected> Error: foobar'));
36+
promiseResolve(promise, 42);
37+
assert(inspect(promise).includes('<rejected> Error: foobar'));
38+
promise.catch(common.mustCall((value) => {
39+
assert.strictEqual(value, error);
40+
}));
41+
}

0 commit comments

Comments
 (0)