1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ScriptPromiseResolver_h
#define ScriptPromiseResolver_h
#include "bindings/core/v8/ScopedPersistent.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/ToV8.h"
#include "core/dom/ActiveDOMObject.h"
#include "core/dom/ExecutionContext.h"
#include "platform/Timer.h"
#include "wtf/RefCounted.h"
#include <v8.h>
namespace blink {
// This class wraps v8::Promise::Resolver and provides the following
// functionalities.
// - A ScriptPromiseResolver retains a ScriptState. A caller
// can call resolve or reject from outside of a V8 context.
// - This class is an ActiveDOMObject and keeps track of the associated
// ExecutionContext state. When the ExecutionContext is suspended,
// resolve or reject will be delayed. When it is stopped, resolve or reject
// will be ignored.
class ScriptPromiseResolver : public RefCountedWillBeRefCountedGarbageCollected<ScriptPromiseResolver>, public ActiveDOMObject {
WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(ScriptPromiseResolver);
WTF_MAKE_NONCOPYABLE(ScriptPromiseResolver);
public:
static PassRefPtrWillBeRawPtr<ScriptPromiseResolver> create(ScriptState* scriptState)
{
RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = adoptRefWillBeNoop(new ScriptPromiseResolver(scriptState));
resolver->suspendIfNeeded();
return resolver.release();
}
virtual ~ScriptPromiseResolver()
{
// This assertion fails if:
// - promise() is called at least once and
// - this resolver is destructed before it is resolved, rejected or
// the associated ExecutionContext is stopped.
ASSERT(m_state == ResolvedOrRejected || !m_isPromiseCalled);
}
// Anything that can be passed to toV8 can be passed to this function.
template<typename T>
void resolve(T value)
{
resolveOrReject(value, Resolving);
}
// Anything that can be passed to toV8 can be passed to this function.
template<typename T>
void reject(T value)
{
resolveOrReject(value, Rejecting);
}
void resolve() { resolve(ToV8UndefinedGenerator()); }
void reject() { reject(ToV8UndefinedGenerator()); }
ScriptState* scriptState() { return m_scriptState.get(); }
// Note that an empty ScriptPromise will be returned after resolve or
// reject is called.
ScriptPromise promise()
{
#if ENABLE(ASSERT)
m_isPromiseCalled = true;
#endif
return m_resolver.promise();
}
ScriptState* scriptState() const { return m_scriptState.get(); }
// ActiveDOMObject implementation.
virtual void suspend() override;
virtual void resume() override;
virtual void stop() override;
// Once this function is called this resolver stays alive while the
// promise is pending and the associated ExecutionContext isn't stopped.
void keepAliveWhilePending();
virtual void trace(Visitor*) override;
protected:
// You need to call suspendIfNeeded after the construction because
// this is an ActiveDOMObject.
explicit ScriptPromiseResolver(ScriptState*);
private:
typedef ScriptPromise::InternalResolver Resolver;
enum ResolutionState {
Pending,
Resolving,
Rejecting,
ResolvedOrRejected,
};
enum LifetimeMode {
Default,
KeepAliveWhilePending,
};
template<typename T>
void resolveOrReject(T value, ResolutionState newState)
{
if (m_state != Pending || !executionContext() || executionContext()->activeDOMObjectsAreStopped())
return;
ASSERT(newState == Resolving || newState == Rejecting);
m_state = newState;
// Retain this object until it is actually resolved or rejected.
// |deref| will be called in |clear|.
ref();
ScriptState::Scope scope(m_scriptState.get());
m_value.set(
m_scriptState->isolate(),
toV8(value, m_scriptState->context()->Global(), m_scriptState->isolate()));
if (!executionContext()->activeDOMObjectsAreSuspended())
resolveOrRejectImmediately();
}
void resolveOrRejectImmediately();
void onTimerFired(Timer<ScriptPromiseResolver>*);
void clear();
ResolutionState m_state;
const RefPtr<ScriptState> m_scriptState;
LifetimeMode m_mode;
Timer<ScriptPromiseResolver> m_timer;
Resolver m_resolver;
ScopedPersistent<v8::Value> m_value;
#if ENABLE(ASSERT)
// True if promise() is called.
bool m_isPromiseCalled;
#endif
};
} // namespace blink
#endif // ScriptPromiseResolver_h
|