Introduce v8::Promise::Then(context, on_fulfilled, on_rejected)

Currently v8::Promise::Then takes only one handler. It should take two handlers,
on_fulfilled and on_rejected like ECMAScript Promise.

Bug: chromium:912848
Change-Id: I08a20990a27b3f8621225fad42a8de1dad67796f
Reviewed-on: https://chromium-review.googlesource.com/c/1375509
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58204}
This commit is contained in:
Yutaka Hirano 2018-12-13 12:41:05 +09:00 committed by Commit Bot
parent fe0c99ad43
commit 228b362a52
3 changed files with 134 additions and 1 deletions

View File

@ -4124,6 +4124,10 @@ class V8_EXPORT Promise : public Object {
V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Then(Local<Context> context,
Local<Function> handler);
V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Then(Local<Context> context,
Local<Function> on_fulfilled,
Local<Function> on_rejected);
/**
* Returns true if the promise has at least one derived promise, and
* therefore resolve/reject handlers (including default handler).

View File

@ -7285,6 +7285,20 @@ MaybeLocal<Promise> Promise::Then(Local<Context> context,
RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result)));
}
MaybeLocal<Promise> Promise::Then(Local<Context> context,
Local<Function> on_fulfilled,
Local<Function> on_rejected) {
PREPARE_FOR_EXECUTION(context, Promise, Then, Promise);
auto self = Utils::OpenHandle(this);
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*on_fulfilled),
Utils::OpenHandle(*on_rejected)};
i::Handle<i::Object> result;
has_pending_exception = !i::Execution::Call(isolate, isolate->promise_then(),
self, arraysize(argv), argv)
.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(Promise);
RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result)));
}
bool Promise::HasHandler() {
i::Handle<i::JSReceiver> promise = Utils::OpenHandle(this);

View File

@ -24693,7 +24693,7 @@ TEST(Promises) {
CHECK(r->IsPromise());
}
// Promise.Then(on_fulfilled)
TEST(PromiseThen) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
@ -24790,6 +24790,121 @@ TEST(PromiseThen) {
.FromJust());
}
// Promise.Then(on_fulfilled, on_rejected)
TEST(PromiseThen2) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
v8::HandleScope scope(isolate);
Local<Object> global = context->Global();
// Creation.
Local<v8::Promise::Resolver> pr =
v8::Promise::Resolver::New(context.local()).ToLocalChecked();
Local<v8::Promise> p = pr->GetPromise();
CHECK(p->IsPromise());
pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
// Chaining non-pending promises.
CompileRun(
"var x1 = 0;\n"
"var x2 = 0;\n"
"function f1(x) { x1 = x; return x+1 };\n"
"function f2(x) { x2 = x; return x+1 };\n"
"function f3(x) { throw x + 100 };\n");
Local<Function> f1 = Local<Function>::Cast(
global->Get(context.local(), v8_str("f1")).ToLocalChecked());
Local<Function> f2 = Local<Function>::Cast(
global->Get(context.local(), v8_str("f2")).ToLocalChecked());
Local<Function> f3 = Local<Function>::Cast(
global->Get(context.local(), v8_str("f3")).ToLocalChecked());
// Then
CompileRun("x1 = x2 = 0;");
Local<v8::Promise> a = p->Then(context.local(), f1, f2).ToLocalChecked();
CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
isolate->RunMicrotasks();
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
Local<v8::Promise> b = a->Then(context.local(), f3, f2).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
Local<v8::Promise> c = b->Then(context.local(), f1, f2).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
v8::Local<v8::Promise> d = c->Then(context.local(), f1, f2).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
v8::Local<v8::Promise> e = d->Then(context.local(), f3, f2).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
v8::Local<v8::Promise> f = e->Then(context.local(), f1, f3).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
f->Then(context.local(), f1, f2).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
CHECK_EQ(304, global->Get(context.local(), v8_str("x2"))
.ToLocalChecked()
->Int32Value(context.local())
.FromJust());
}
TEST(PromiseStateAndValue) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();