Commit c27b424e authored by yhirano@chromium.org's avatar yhirano@chromium.org

ScriptPromise implementation for V8 Promises

Add the implementation for V8 Promises in ScriptPromise and ScriptPromiseResolver so that:
 - They can handle V8 Promises correctly.
 - ScriptPromise creates a V8 Promise if ScriptPromiseOnV8Promise turns on.

Add ScriptPromiseOnV8Promise runtime enabled flag which is always off.
Add Layout tests for ScriptPromise.

BUG=352552

Review URL: https://codereview.chromium.org/197213007

git-svn-id: svn://svn.chromium.org/blink/trunk@169516 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent b341841d
Test Promise constructor inside Blink.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
constructor = function Promise() { [native code] }
then = function then() { [native code] }
catch = function catch() { [native code] }
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
description('Test Promise constructor inside Blink.');
var resolve;
var promise = window.internals.createPromise();
debug('constructor = ' + promise.constructor);
debug('then = ' + promise.then);
debug('catch = ' + promise.catch);
</script>
</body>
</html>
Test Promise reject inside Blink.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS result is 42
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
description('Test Promise reject inside Blink.');
window.jsTestIsAsync = true;
var reject;
var promise = new Promise(function(res, rej) { reject = rej; });
var blinkPromise = internals.createRejectedPromise(42);
promise.then(function() {
testFailed('fulfilled');
}, function(value) {
return blinkPromise;
}).then(function() {
testFailed('fulfilled');
}, function(value) {
result = value;
shouldBe('result', '42');
}).then(finishJSTest, finishJSTest);
reject(118);
</script>
</body>
</html>
Test Promise resolve inside Blink.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS result is 42
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
description('Test Promise resolve inside Blink.');
window.jsTestIsAsync = true;
var result;
var resolve;
var promise = new Promise(function(res) { resolve = res; });
var blinkPromise = internals.createResolvedPromise(promise);
promise.then(function(value) {
return blinkPromise;
}).then(function(value) {
result = value;
shouldBe('result', '42');
}).then(finishJSTest, finishJSTest);
resolve(42);
</script>
</body>
</html>
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "config.h" #include "config.h"
#include "bindings/v8/ScriptPromise.h" #include "bindings/v8/ScriptPromise.h"
#include "RuntimeEnabledFeatures.h"
#include "bindings/v8/V8Binding.h" #include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h" #include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/custom/V8PromiseCustom.h" #include "bindings/v8/custom/V8PromiseCustom.h"
...@@ -41,7 +42,10 @@ namespace WebCore { ...@@ -41,7 +42,10 @@ namespace WebCore {
ScriptPromise::ScriptPromise(v8::Handle<v8::Value> value, v8::Isolate* isolate) ScriptPromise::ScriptPromise(v8::Handle<v8::Value> value, v8::Isolate* isolate)
{ {
if (value.IsEmpty() || !V8PromiseCustom::isPromise(value, isolate)) { if (value.IsEmpty())
return;
if (!V8PromiseCustom::isPromise(value, isolate) && !value->IsPromise()) {
m_promise = ScriptValue(v8::Handle<v8::Value>(), isolate); m_promise = ScriptValue(v8::Handle<v8::Value>(), isolate);
V8ThrowException::throwTypeError("the given value is not a Promise", isolate); V8ThrowException::throwTypeError("the given value is not a Promise", isolate);
return; return;
...@@ -51,29 +55,34 @@ ScriptPromise::ScriptPromise(v8::Handle<v8::Value> value, v8::Isolate* isolate) ...@@ -51,29 +55,34 @@ ScriptPromise::ScriptPromise(v8::Handle<v8::Value> value, v8::Isolate* isolate)
ScriptPromise ScriptPromise::then(PassOwnPtr<ScriptFunction> onFulfilled, PassOwnPtr<ScriptFunction> onRejected) ScriptPromise ScriptPromise::then(PassOwnPtr<ScriptFunction> onFulfilled, PassOwnPtr<ScriptFunction> onRejected)
{ {
if (m_promise.hasNoValue() || !m_promise.isObject()) if (m_promise.hasNoValue())
return ScriptPromise(); return ScriptPromise();
v8::Handle<v8::Object> promise = m_promise.v8Value().As<v8::Object>();
return ScriptPromise(V8PromiseCustom::then(promise, adoptByGarbageCollector(onFulfilled), adoptByGarbageCollector(onRejected), isolate()), isolate());
}
ScriptPromise ScriptPromise::createPending() v8::Local<v8::Object> promise = m_promise.v8Value().As<v8::Object>();
{ v8::Local<v8::Function> v8OnFulfilled = adoptByGarbageCollector(onFulfilled);
v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Local<v8::Function> v8OnRejected = adoptByGarbageCollector(onRejected);
ASSERT(isolate->InContext());
v8::Handle<v8::Object> promise = V8PromiseCustom::createPromise(v8::Object::New(isolate), isolate);
return ScriptPromise(promise, isolate);
}
ScriptPromise ScriptPromise::createPending(ExecutionContext* context) if (V8PromiseCustom::isPromise(promise, isolate()))
{ return ScriptPromise(V8PromiseCustom::then(promise, v8OnFulfilled, v8OnRejected, isolate()), isolate());
ASSERT(context);
v8::Isolate* isolate = toIsolate(context); ASSERT(promise->IsPromise());
ASSERT(isolate->InContext()); // Return this Promise if no handlers are given.
v8::Handle<v8::Context> v8Context = toV8Context(context, DOMWrapperWorld::current(isolate)); // In fact it is not the exact bahavior of Promise.prototype.then
v8::Handle<v8::Object> creationContext = v8Context.IsEmpty() ? v8::Object::New(isolate) : v8Context->Global(); // but that is not a problem in this case.
v8::Handle<v8::Object> promise = V8PromiseCustom::createPromise(creationContext, isolate); v8::Local<v8::Promise> resultPromise = promise.As<v8::Promise>();
return ScriptPromise(promise, isolate); // FIXME: Use Then once it is introduced.
if (!v8OnFulfilled.IsEmpty()) {
resultPromise = resultPromise->Chain(v8OnFulfilled);
if (resultPromise.IsEmpty()) {
// v8::Promise::Chain may return an empty value, for example when
// the stack is exhausted.
return ScriptPromise();
}
}
if (!v8OnRejected.IsEmpty())
resultPromise = resultPromise->Catch(v8OnRejected);
return ScriptPromise(resultPromise, isolate());
} }
ScriptPromise ScriptPromise::cast(const ScriptValue& value) ScriptPromise ScriptPromise::cast(const ScriptValue& value)
...@@ -82,9 +91,19 @@ ScriptPromise ScriptPromise::cast(const ScriptValue& value) ...@@ -82,9 +91,19 @@ ScriptPromise ScriptPromise::cast(const ScriptValue& value)
return ScriptPromise(); return ScriptPromise();
v8::Local<v8::Value> v8Value(value.v8Value()); v8::Local<v8::Value> v8Value(value.v8Value());
v8::Isolate* isolate = value.isolate(); v8::Isolate* isolate = value.isolate();
if (V8PromiseCustom::isPromise(v8Value, isolate)) { if (V8PromiseCustom::isPromise(v8Value, isolate) || v8Value->IsPromise()) {
return ScriptPromise(v8Value, isolate); return ScriptPromise(v8Value, isolate);
} }
if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled()) {
v8::Local<v8::Promise::Resolver> resolver = v8::Promise::Resolver::New(isolate);
if (resolver.IsEmpty()) {
// The Promise constructor may return an empty value, for example
// when the stack is exhausted.
return ScriptPromise();
}
resolver->Resolve(v8Value);
return ScriptPromise(resolver->GetPromise(), isolate);
}
return ScriptPromise(V8PromiseCustom::toPromise(v8Value, isolate), isolate); return ScriptPromise(V8PromiseCustom::toPromise(v8Value, isolate), isolate);
} }
......
...@@ -99,12 +99,6 @@ public: ...@@ -99,12 +99,6 @@ public:
static ScriptPromise cast(const ScriptValue& /*value*/); static ScriptPromise cast(const ScriptValue& /*value*/);
private: private:
friend class ScriptPromiseResolver;
static ScriptPromise createPending();
static ScriptPromise createPending(ExecutionContext*);
static ScriptPromise createPending(v8::Isolate*) { return createPending(); }
ScriptValue m_promise; ScriptValue m_promise;
}; };
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "config.h" #include "config.h"
#include "bindings/v8/ScriptPromiseResolver.h" #include "bindings/v8/ScriptPromiseResolver.h"
#include "RuntimeEnabledFeatures.h"
#include "bindings/v8/ScriptState.h" #include "bindings/v8/ScriptState.h"
#include "bindings/v8/ScriptValue.h" #include "bindings/v8/ScriptValue.h"
#include "bindings/v8/V8Binding.h" #include "bindings/v8/V8Binding.h"
...@@ -43,14 +44,28 @@ namespace WebCore { ...@@ -43,14 +44,28 @@ namespace WebCore {
ScriptPromiseResolver::ScriptPromiseResolver(ExecutionContext* context) ScriptPromiseResolver::ScriptPromiseResolver(ExecutionContext* context)
: m_isolate(toIsolate(context)) : m_isolate(toIsolate(context))
, m_promise(ScriptPromise::createPending(context))
{ {
ASSERT(context);
v8::Isolate* isolate = toIsolate(context);
ASSERT(isolate->InContext());
if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled()) {
m_resolver = ScriptValue(v8::Promise::Resolver::New(isolate), isolate);
} else {
v8::Handle<v8::Context> v8Context = toV8Context(context, DOMWrapperWorld::current(isolate));
v8::Handle<v8::Object> creationContext = v8Context.IsEmpty() ? v8::Object::New(isolate) : v8Context->Global();
m_promise = ScriptPromise(V8PromiseCustom::createPromise(creationContext, isolate), isolate);
}
} }
ScriptPromiseResolver::ScriptPromiseResolver(v8::Isolate* isolate) ScriptPromiseResolver::ScriptPromiseResolver(v8::Isolate* isolate)
: m_isolate(isolate) : m_isolate(isolate)
, m_promise(ScriptPromise::createPending(isolate))
{ {
ASSERT(isolate->InContext());
if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled()) {
m_resolver = ScriptValue(v8::Promise::Resolver::New(isolate), isolate);
} else {
m_promise = ScriptPromise(V8PromiseCustom::createPromise(v8::Object::New(isolate), isolate), isolate);
}
} }
ScriptPromiseResolver::~ScriptPromiseResolver() ScriptPromiseResolver::~ScriptPromiseResolver()
...@@ -59,6 +74,17 @@ ScriptPromiseResolver::~ScriptPromiseResolver() ...@@ -59,6 +74,17 @@ ScriptPromiseResolver::~ScriptPromiseResolver()
// to be in a v8 context. // to be in a v8 context.
m_promise.clear(); m_promise.clear();
m_resolver.clear();
}
ScriptPromise ScriptPromiseResolver::promise()
{
ASSERT(m_isolate->InContext());
if (!m_resolver.hasNoValue()) {
v8::Local<v8::Promise::Resolver> v8Resolver = m_resolver.v8Value().As<v8::Promise::Resolver>();
return ScriptPromise(v8Resolver->GetPromise(), m_isolate);
}
return m_promise;
} }
PassRefPtr<ScriptPromiseResolver> ScriptPromiseResolver::create(ExecutionContext* context) PassRefPtr<ScriptPromiseResolver> ScriptPromiseResolver::create(ExecutionContext* context)
...@@ -74,33 +100,32 @@ PassRefPtr<ScriptPromiseResolver> ScriptPromiseResolver::create(v8::Isolate* iso ...@@ -74,33 +100,32 @@ PassRefPtr<ScriptPromiseResolver> ScriptPromiseResolver::create(v8::Isolate* iso
return adoptRef(new ScriptPromiseResolver(isolate)); return adoptRef(new ScriptPromiseResolver(isolate));
} }
bool ScriptPromiseResolver::isPending() const
{
ASSERT(m_isolate->InContext());
if (m_promise.hasNoValue())
return false;
v8::Local<v8::Object> promise = m_promise.v8Value().As<v8::Object>();
v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
V8PromiseCustom::PromiseState state = V8PromiseCustom::getState(internal);
return state == V8PromiseCustom::Pending;
}
void ScriptPromiseResolver::resolve(v8::Handle<v8::Value> value) void ScriptPromiseResolver::resolve(v8::Handle<v8::Value> value)
{ {
ASSERT(m_isolate->InContext()); ASSERT(m_isolate->InContext());
if (!isPending()) if (!m_resolver.hasNoValue()) {
return; m_resolver.v8Value().As<v8::Promise::Resolver>()->Resolve(value);
V8PromiseCustom::resolve(m_promise.v8Value().As<v8::Object>(), value, m_isolate); } else if (!m_promise.hasNoValue()) {
v8::Local<v8::Object> promise = m_promise.v8Value().As<v8::Object>();
ASSERT(V8PromiseCustom::isPromise(promise, m_isolate));
V8PromiseCustom::resolve(promise, value, m_isolate);
}
m_promise.clear(); m_promise.clear();
m_resolver.clear();
} }
void ScriptPromiseResolver::reject(v8::Handle<v8::Value> value) void ScriptPromiseResolver::reject(v8::Handle<v8::Value> value)
{ {
ASSERT(m_isolate->InContext()); ASSERT(m_isolate->InContext());
if (!isPending()) if (!m_resolver.hasNoValue()) {
return; m_resolver.v8Value().As<v8::Promise::Resolver>()->Reject(value);
V8PromiseCustom::reject(m_promise.v8Value().As<v8::Object>(), value, m_isolate); } else if (!m_promise.hasNoValue()) {
v8::Local<v8::Object> promise = m_promise.v8Value().As<v8::Object>();
ASSERT(V8PromiseCustom::isPromise(promise, m_isolate));
V8PromiseCustom::reject(promise, value, m_isolate);
}
m_promise.clear(); m_promise.clear();
m_resolver.clear();
} }
void ScriptPromiseResolver::resolve(ScriptValue value) void ScriptPromiseResolver::resolve(ScriptValue value)
......
...@@ -51,7 +51,7 @@ class ExecutionContext; ...@@ -51,7 +51,7 @@ class ExecutionContext;
// ScriptPromiseResolver holds a PromiseResolver. // ScriptPromiseResolver holds a PromiseResolver.
// Here is a typical usage: // Here is a typical usage:
// 1. Create a ScriptPromiseResolver. // 1. Create a ScriptPromiseResolver.
// 2. Pass the promise object of the holder to a JavaScript program // 2. Pass the associated promise object to a JavaScript program
// (such as XMLHttpRequest return value). // (such as XMLHttpRequest return value).
// 3. Call resolve or reject when the operation completes or // 3. Call resolve or reject when the operation completes or
// the operation fails respectively. // the operation fails respectively.
...@@ -63,7 +63,10 @@ class ExecutionContext; ...@@ -63,7 +63,10 @@ class ExecutionContext;
// To prevent memory leaks, you should release the reference manually // To prevent memory leaks, you should release the reference manually
// by calling resolve or reject. // by calling resolve or reject.
// Destroying the object will also release the reference. // Destroying the object will also release the reference.
// // Note that ScriptPromiseResolver::promise returns an empty value when the
// resolver is already resolved or rejected. If you want to resolve a resolver
// immediately and return the associated promise, you should get the promise
// before resolving.
class ScriptPromiseResolver : public RefCounted<ScriptPromiseResolver> { class ScriptPromiseResolver : public RefCounted<ScriptPromiseResolver> {
WTF_MAKE_NONCOPYABLE(ScriptPromiseResolver); WTF_MAKE_NONCOPYABLE(ScriptPromiseResolver);
public: public:
...@@ -76,14 +79,10 @@ public: ...@@ -76,14 +79,10 @@ public:
// entering a v8 context. // entering a v8 context.
~ScriptPromiseResolver(); ~ScriptPromiseResolver();
// Return true if the promise object is in pending state. // Returns the underlying Promise.
bool isPending() const; // Note that the underlying Promise is cleared when |resolve| or |reject|
// is called.
ScriptPromise promise() ScriptPromise promise();
{
ASSERT(m_promise.isolate()->InContext());
return m_promise;
}
// To use following template methods, T must be a DOM class. // To use following template methods, T must be a DOM class.
...@@ -141,7 +140,10 @@ private: ...@@ -141,7 +140,10 @@ private:
void reject(v8::Handle<v8::Value>); void reject(v8::Handle<v8::Value>);
v8::Isolate* m_isolate; v8::Isolate* m_isolate;
// Used when scriptPromiseOnV8Promise is disabled.
ScriptPromise m_promise; ScriptPromise m_promise;
// Used when scriptPromiseOnV8Promise is enabled.
ScriptValue m_resolver;
}; };
template<typename T> template<typename T>
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "config.h" #include "config.h"
#include "bindings/v8/ScriptPromiseResolver.h" #include "bindings/v8/ScriptPromiseResolver.h"
#include "RuntimeEnabledFeatures.h"
#include "bindings/v8/DOMWrapperWorld.h" #include "bindings/v8/DOMWrapperWorld.h"
#include "bindings/v8/ScriptPromise.h" #include "bindings/v8/ScriptPromise.h"
#include "bindings/v8/V8Binding.h" #include "bindings/v8/V8Binding.h"
...@@ -90,20 +91,21 @@ private: ...@@ -90,20 +91,21 @@ private:
TEST_F(ScriptPromiseResolverTest, initialState) TEST_F(ScriptPromiseResolverTest, initialState)
{ {
EXPECT_TRUE(m_resolver->isPending()); if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled())
return;
EXPECT_EQ(V8PromiseCustom::Pending, state()); EXPECT_EQ(V8PromiseCustom::Pending, state());
EXPECT_TRUE(result()->IsUndefined()); EXPECT_TRUE(result()->IsUndefined());
} }
TEST_F(ScriptPromiseResolverTest, resolve) TEST_F(ScriptPromiseResolverTest, resolve)
{ {
EXPECT_TRUE(m_resolver->isPending()); if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled())
return;
EXPECT_EQ(V8PromiseCustom::Pending, state()); EXPECT_EQ(V8PromiseCustom::Pending, state());
EXPECT_TRUE(result()->IsUndefined()); EXPECT_TRUE(result()->IsUndefined());
m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate)); m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate));
EXPECT_FALSE(m_resolver->isPending());
EXPECT_EQ(V8PromiseCustom::Fulfilled, state()); EXPECT_EQ(V8PromiseCustom::Fulfilled, state());
ASSERT_TRUE(result()->IsNumber()); ASSERT_TRUE(result()->IsNumber());
EXPECT_EQ(3, result().As<v8::Integer>()->Value()); EXPECT_EQ(3, result().As<v8::Integer>()->Value());
...@@ -111,13 +113,13 @@ TEST_F(ScriptPromiseResolverTest, resolve) ...@@ -111,13 +113,13 @@ TEST_F(ScriptPromiseResolverTest, resolve)
TEST_F(ScriptPromiseResolverTest, reject) TEST_F(ScriptPromiseResolverTest, reject)
{ {
EXPECT_TRUE(m_resolver->isPending()); if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled())
return;
EXPECT_EQ(V8PromiseCustom::Pending, state()); EXPECT_EQ(V8PromiseCustom::Pending, state());
EXPECT_TRUE(result()->IsUndefined()); EXPECT_TRUE(result()->IsUndefined());
m_resolver->reject(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate)); m_resolver->reject(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate));
EXPECT_FALSE(m_resolver->isPending());
EXPECT_EQ(V8PromiseCustom::Rejected, state()); EXPECT_EQ(V8PromiseCustom::Rejected, state());
ASSERT_TRUE(result()->IsNumber()); ASSERT_TRUE(result()->IsNumber());
EXPECT_EQ(3, result().As<v8::Integer>()->Value()); EXPECT_EQ(3, result().As<v8::Integer>()->Value());
...@@ -125,19 +127,18 @@ TEST_F(ScriptPromiseResolverTest, reject) ...@@ -125,19 +127,18 @@ TEST_F(ScriptPromiseResolverTest, reject)
TEST_F(ScriptPromiseResolverTest, resolveOverResolve) TEST_F(ScriptPromiseResolverTest, resolveOverResolve)
{ {
EXPECT_TRUE(m_resolver->isPending()); if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled())
return;
EXPECT_EQ(V8PromiseCustom::Pending, state()); EXPECT_EQ(V8PromiseCustom::Pending, state());
EXPECT_TRUE(result()->IsUndefined()); EXPECT_TRUE(result()->IsUndefined());
m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate)); m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate));
EXPECT_FALSE(m_resolver->isPending());
EXPECT_EQ(V8PromiseCustom::Fulfilled, state()); EXPECT_EQ(V8PromiseCustom::Fulfilled, state());
ASSERT_TRUE(result()->IsNumber()); ASSERT_TRUE(result()->IsNumber());
EXPECT_EQ(3, result().As<v8::Integer>()->Value()); EXPECT_EQ(3, result().As<v8::Integer>()->Value());
m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 4), m_isolate)); m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 4), m_isolate));
EXPECT_FALSE(m_resolver->isPending());
EXPECT_EQ(V8PromiseCustom::Fulfilled, state()); EXPECT_EQ(V8PromiseCustom::Fulfilled, state());
ASSERT_TRUE(result()->IsNumber()); ASSERT_TRUE(result()->IsNumber());
EXPECT_EQ(3, result().As<v8::Integer>()->Value()); EXPECT_EQ(3, result().As<v8::Integer>()->Value());
...@@ -145,19 +146,18 @@ TEST_F(ScriptPromiseResolverTest, resolveOverResolve) ...@@ -145,19 +146,18 @@ TEST_F(ScriptPromiseResolverTest, resolveOverResolve)
TEST_F(ScriptPromiseResolverTest, rejectOverResolve) TEST_F(ScriptPromiseResolverTest, rejectOverResolve)
{ {
EXPECT_TRUE(m_resolver->isPending()); if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled())
return;
EXPECT_EQ(V8PromiseCustom::Pending, state()); EXPECT_EQ(V8PromiseCustom::Pending, state());
EXPECT_TRUE(result()->IsUndefined()); EXPECT_TRUE(result()->IsUndefined());
m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate)); m_resolver->resolve(ScriptValue(v8::Integer::New(m_isolate, 3), m_isolate));
EXPECT_FALSE(m_resolver->isPending());
EXPECT_EQ(V8PromiseCustom::Fulfilled, state()); EXPECT_EQ(V8PromiseCustom::Fulfilled, state());
ASSERT_TRUE(result()->IsNumber()); ASSERT_TRUE(result()->IsNumber());
EXPECT_EQ(3, result().As<v8::Integer>()->Value()); EXPECT_EQ(3, result().As<v8::Integer>()->Value());
m_resolver->reject(ScriptValue(v8::Integer::New(m_isolate, 4), m_isolate)); m_resolver->reject(ScriptValue(v8::Integer::New(m_isolate, 4), m_isolate));
EXPECT_FALSE(m_resolver->isPending());
EXPECT_EQ(V8PromiseCustom::Fulfilled, state()); EXPECT_EQ(V8PromiseCustom::Fulfilled, state());
ASSERT_TRUE(result()->IsNumber()); ASSERT_TRUE(result()->IsNumber());
EXPECT_EQ(3, result().As<v8::Integer>()->Value()); EXPECT_EQ(3, result().As<v8::Integer>()->Value());
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "bindings/v8/ExceptionState.h" #include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ScriptFunction.h" #include "bindings/v8/ScriptFunction.h"
#include "bindings/v8/ScriptPromise.h" #include "bindings/v8/ScriptPromise.h"
#include "bindings/v8/ScriptPromiseResolver.h"
#include "bindings/v8/SerializedScriptValue.h" #include "bindings/v8/SerializedScriptValue.h"
#include "bindings/v8/V8ThrowException.h" #include "bindings/v8/V8ThrowException.h"
#include "core/animation/DocumentTimeline.h" #include "core/animation/DocumentTimeline.h"
...@@ -2387,6 +2388,27 @@ private: ...@@ -2387,6 +2388,27 @@ private:
} // namespace } // namespace
ScriptPromise Internals::createPromise(ExecutionContext* context)
{
return ScriptPromiseResolver::create(context)->promise();
}
ScriptPromise Internals::createResolvedPromise(ExecutionContext* context, ScriptValue value)
{
RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(context);
ScriptPromise promise = resolver->promise();
resolver->resolve(value);
return promise;
}
ScriptPromise Internals::createRejectedPromise(ExecutionContext* context, ScriptValue value)
{
RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(context);
ScriptPromise promise = resolver->promise();
resolver->reject(value);
return promise;
}
ScriptPromise Internals::addOneToPromise(ExecutionContext* context, ScriptPromise promise) ScriptPromise Internals::addOneToPromise(ExecutionContext* context, ScriptPromise promise)
{ {
return promise.then(AddOneFunction::create(context)); return promise.then(AddOneFunction::create(context));
......
...@@ -310,6 +310,9 @@ public: ...@@ -310,6 +310,9 @@ public:
void setShouldRevealPassword(Element*, bool, ExceptionState&); void setShouldRevealPassword(Element*, bool, ExceptionState&);
ScriptPromise createPromise(ExecutionContext*);
ScriptPromise createResolvedPromise(ExecutionContext*, ScriptValue);
ScriptPromise createRejectedPromise(ExecutionContext*, ScriptValue);
ScriptPromise addOneToPromise(ExecutionContext*, ScriptPromise); ScriptPromise addOneToPromise(ExecutionContext*, ScriptPromise);
void trace(Visitor*); void trace(Visitor*);
......
...@@ -278,6 +278,9 @@ ...@@ -278,6 +278,9 @@
[RaisesException] void setShouldRevealPassword(Element element, boolean reveal); [RaisesException] void setShouldRevealPassword(Element element, boolean reveal);
[CallWith=ExecutionContext] Promise createPromise();
[CallWith=ExecutionContext] Promise createResolvedPromise(any value);
[CallWith=ExecutionContext] Promise createRejectedPromise(any reason);
[CallWith=ExecutionContext] Promise addOneToPromise(Promise promise); [CallWith=ExecutionContext] Promise addOneToPromise(Promise promise);
void startSpeechInput(Element element); void startSpeechInput(Element element);
......
...@@ -121,6 +121,7 @@ Touch status=stable ...@@ -121,6 +121,7 @@ Touch status=stable
TouchIconLoading TouchIconLoading
UserSelectAll status=experimental UserSelectAll status=experimental
ScriptPromiseOnV8Promise
VideoTrack depends_on=Media, status=stable VideoTrack depends_on=Media, status=stable
WebAnimationsSVG WebAnimationsSVG
WebAnimationsAPI status=experimental WebAnimationsAPI status=experimental
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment