Browse Source

util: use V8 C++ API for inspecting Promises

PR-URL: https://github.com/nodejs/node/pull/12254
Refs: https://github.com/nodejs/node/issues/11875
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Josh Gavant <josh.gavant@outlook.com>
v6
Timothy Gu 8 years ago
parent
commit
a37273c1e4
  1. 62
      lib/util.js
  2. 30
      src/node_util.cc

62
lib/util.js

@ -302,16 +302,6 @@ function ensureDebugIsInitialized() {
}
function inspectPromise(p) {
// Only create a mirror if the object is a Promise.
if (!binding.isPromise(p))
return null;
ensureDebugIsInitialized();
const mirror = Debug.MakeMirror(p, true);
return {status: mirror.status(), value: mirror.promiseValue().value_};
}
function formatValue(ctx, value, recurseTimes) {
if (ctx.showProxy &&
((typeof value === 'object' && value !== null) ||
@ -527,30 +517,25 @@ function formatValue(ctx, value, recurseTimes) {
'byteOffset',
'buffer');
}
} else if (binding.isPromise(value)) {
braces = ['{', '}'];
formatter = formatPromise;
} else if (binding.isMapIterator(value)) {
constructor = { name: 'MapIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else if (binding.isSetIterator(value)) {
constructor = { name: 'SetIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else {
var promiseInternals = inspectPromise(value);
if (promiseInternals) {
braces = ['{', '}'];
formatter = formatPromise;
} else {
if (binding.isMapIterator(value)) {
constructor = { name: 'MapIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else if (binding.isSetIterator(value)) {
constructor = { name: 'SetIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else {
// Unset the constructor to prevent "Object {...}" for ordinary objects.
if (constructor && constructor.name === 'Object')
constructor = null;
braces = ['{', '}'];
empty = true; // No other data than keys.
}
}
// Unset the constructor to prevent "Object {...}" for ordinary objects.
if (constructor && constructor.name === 'Object')
constructor = null;
braces = ['{', '}'];
empty = true; // No other data than keys.
}
empty = empty === true && keys.length === 0;
@ -779,14 +764,15 @@ function formatCollectionIterator(ctx, value, recurseTimes, visibleKeys, keys) {
}
function formatPromise(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
var internals = inspectPromise(value);
if (internals.status === 'pending') {
const output = [];
const [state, result] = binding.getPromiseDetails(value);
if (state === binding.kPending) {
output.push('<pending>');
} else {
var nextRecurseTimes = recurseTimes === null ? null : recurseTimes - 1;
var str = formatValue(ctx, internals.value, nextRecurseTimes);
if (internals.status === 'rejected') {
var str = formatValue(ctx, result, nextRecurseTimes);
if (state === binding.kRejected) {
output.push('<rejected> ' + str);
} else {
output.push(str);

30
src/node_util.cc

@ -14,6 +14,7 @@ using v8::Integer;
using v8::Local;
using v8::Object;
using v8::Private;
using v8::Promise;
using v8::Proxy;
using v8::Value;
@ -43,6 +44,24 @@ using v8::Value;
VALUE_METHOD_MAP(V)
#undef V
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
// Return undefined if it's not a Promise.
if (!args[0]->IsPromise())
return;
auto isolate = args.GetIsolate();
Local<Promise> promise = args[0].As<Promise>();
Local<Array> ret = Array::New(isolate, 2);
int state = promise->State();
ret->Set(0, Integer::New(isolate, state));
if (state != Promise::PromiseState::kPending)
ret->Set(1, promise->Result());
args.GetReturnValue().Set(ret);
}
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
// Return undefined if it's not a proxy.
if (!args[0]->IsProxy())
@ -148,8 +167,19 @@ void Initialize(Local<Object> target,
Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX),
v8::ReadOnly).FromJust();
#define V(name) \
target->Set(context, \
FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
Integer::New(env->isolate(), Promise::PromiseState::name)) \
.FromJust()
V(kPending);
V(kFulfilled);
V(kRejected);
#undef V
env->SetMethod(target, "getHiddenValue", GetHiddenValue);
env->SetMethod(target, "setHiddenValue", SetHiddenValue);
env->SetMethod(target, "getPromiseDetails", GetPromiseDetails);
env->SetMethod(target, "getProxyDetails", GetProxyDetails);
env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);

Loading…
Cancel
Save