Skip to content

Commit a37273c

Browse files
committed
util: use V8 C++ API for inspecting Promises
PR-URL: #12254 Refs: #11875 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Josh Gavant <[email protected]>
1 parent afd5966 commit a37273c

File tree

2 files changed

+54
-38
lines changed

2 files changed

+54
-38
lines changed

lib/util.js

+24-38
Original file line numberDiff line numberDiff line change
@@ -302,16 +302,6 @@ function ensureDebugIsInitialized() {
302302
}
303303

304304

305-
function inspectPromise(p) {
306-
// Only create a mirror if the object is a Promise.
307-
if (!binding.isPromise(p))
308-
return null;
309-
ensureDebugIsInitialized();
310-
const mirror = Debug.MakeMirror(p, true);
311-
return {status: mirror.status(), value: mirror.promiseValue().value_};
312-
}
313-
314-
315305
function formatValue(ctx, value, recurseTimes) {
316306
if (ctx.showProxy &&
317307
((typeof value === 'object' && value !== null) ||
@@ -527,30 +517,25 @@ function formatValue(ctx, value, recurseTimes) {
527517
'byteOffset',
528518
'buffer');
529519
}
520+
} else if (binding.isPromise(value)) {
521+
braces = ['{', '}'];
522+
formatter = formatPromise;
523+
} else if (binding.isMapIterator(value)) {
524+
constructor = { name: 'MapIterator' };
525+
braces = ['{', '}'];
526+
empty = false;
527+
formatter = formatCollectionIterator;
528+
} else if (binding.isSetIterator(value)) {
529+
constructor = { name: 'SetIterator' };
530+
braces = ['{', '}'];
531+
empty = false;
532+
formatter = formatCollectionIterator;
530533
} else {
531-
var promiseInternals = inspectPromise(value);
532-
if (promiseInternals) {
533-
braces = ['{', '}'];
534-
formatter = formatPromise;
535-
} else {
536-
if (binding.isMapIterator(value)) {
537-
constructor = { name: 'MapIterator' };
538-
braces = ['{', '}'];
539-
empty = false;
540-
formatter = formatCollectionIterator;
541-
} else if (binding.isSetIterator(value)) {
542-
constructor = { name: 'SetIterator' };
543-
braces = ['{', '}'];
544-
empty = false;
545-
formatter = formatCollectionIterator;
546-
} else {
547-
// Unset the constructor to prevent "Object {...}" for ordinary objects.
548-
if (constructor && constructor.name === 'Object')
549-
constructor = null;
550-
braces = ['{', '}'];
551-
empty = true; // No other data than keys.
552-
}
553-
}
534+
// Unset the constructor to prevent "Object {...}" for ordinary objects.
535+
if (constructor && constructor.name === 'Object')
536+
constructor = null;
537+
braces = ['{', '}'];
538+
empty = true; // No other data than keys.
554539
}
555540

556541
empty = empty === true && keys.length === 0;
@@ -779,14 +764,15 @@ function formatCollectionIterator(ctx, value, recurseTimes, visibleKeys, keys) {
779764
}
780765

781766
function formatPromise(ctx, value, recurseTimes, visibleKeys, keys) {
782-
var output = [];
783-
var internals = inspectPromise(value);
784-
if (internals.status === 'pending') {
767+
const output = [];
768+
const [state, result] = binding.getPromiseDetails(value);
769+
770+
if (state === binding.kPending) {
785771
output.push('<pending>');
786772
} else {
787773
var nextRecurseTimes = recurseTimes === null ? null : recurseTimes - 1;
788-
var str = formatValue(ctx, internals.value, nextRecurseTimes);
789-
if (internals.status === 'rejected') {
774+
var str = formatValue(ctx, result, nextRecurseTimes);
775+
if (state === binding.kRejected) {
790776
output.push('<rejected> ' + str);
791777
} else {
792778
output.push(str);

src/node_util.cc

+30
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ using v8::Integer;
1414
using v8::Local;
1515
using v8::Object;
1616
using v8::Private;
17+
using v8::Promise;
1718
using v8::Proxy;
1819
using v8::Value;
1920

@@ -43,6 +44,24 @@ using v8::Value;
4344
VALUE_METHOD_MAP(V)
4445
#undef V
4546

47+
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
48+
// Return undefined if it's not a Promise.
49+
if (!args[0]->IsPromise())
50+
return;
51+
52+
auto isolate = args.GetIsolate();
53+
54+
Local<Promise> promise = args[0].As<Promise>();
55+
Local<Array> ret = Array::New(isolate, 2);
56+
57+
int state = promise->State();
58+
ret->Set(0, Integer::New(isolate, state));
59+
if (state != Promise::PromiseState::kPending)
60+
ret->Set(1, promise->Result());
61+
62+
args.GetReturnValue().Set(ret);
63+
}
64+
4665
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
4766
// Return undefined if it's not a proxy.
4867
if (!args[0]->IsProxy())
@@ -148,8 +167,19 @@ void Initialize(Local<Object> target,
148167
Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX),
149168
v8::ReadOnly).FromJust();
150169

170+
#define V(name) \
171+
target->Set(context, \
172+
FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
173+
Integer::New(env->isolate(), Promise::PromiseState::name)) \
174+
.FromJust()
175+
V(kPending);
176+
V(kFulfilled);
177+
V(kRejected);
178+
#undef V
179+
151180
env->SetMethod(target, "getHiddenValue", GetHiddenValue);
152181
env->SetMethod(target, "setHiddenValue", SetHiddenValue);
182+
env->SetMethod(target, "getPromiseDetails", GetPromiseDetails);
153183
env->SetMethod(target, "getProxyDetails", GetProxyDetails);
154184

155185
env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);

0 commit comments

Comments
 (0)