1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_Promise_h
8 #define mozilla_dom_Promise_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/TypeTraits.h"
13 #include "mozilla/dom/BindingDeclarations.h"
14 #include "nsCycleCollectionParticipant.h"
15 #include "mozilla/dom/PromiseBinding.h"
16 #include "mozilla/dom/ToJSValue.h"
17 #include "mozilla/WeakPtr.h"
18 #include "nsWrapperCache.h"
19 #include "nsAutoPtr.h"
20 #include "js/TypeDecls.h"
22 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
24 class nsIGlobalObject
;
31 class PromiseCallback
;
33 class PromiseNativeHandler
;
34 class PromiseDebugging
;
37 class PromiseReportRejectFeature
: public workers::WorkerFeature
39 // The Promise that owns this feature.
43 explicit PromiseReportRejectFeature(Promise
* aPromise
)
50 Notify(JSContext
* aCx
, workers::Status aStatus
) MOZ_OVERRIDE
;
53 class Promise MOZ_FINAL
: public nsISupports
,
54 public nsWrapperCache
,
55 public SupportsWeakPtr
<Promise
>
57 friend class NativePromiseCallback
;
58 friend class PromiseResolverTask
;
59 friend class PromiseTask
;
60 friend class PromiseReportRejectFeature
;
61 friend class PromiseWorkerProxy
;
62 friend class PromiseWorkerProxyRunnable
;
63 friend class RejectPromiseCallback
;
64 friend class ResolvePromiseCallback
;
65 friend class ThenableResolverTask
;
66 friend class WrapperPromiseCallback
;
71 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
72 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise
)
73 MOZ_DECLARE_REFCOUNTED_TYPENAME(Promise
)
75 // Promise creation tries to create a JS reflector for the Promise, so is
76 // fallible. Furthermore, we don't want to do JS-wrapping on a 0-refcount
77 // object, so we addref before doing that and return the addrefed pointer
79 static already_AddRefed
<Promise
>
80 Create(nsIGlobalObject
* aGlobal
, ErrorResult
& aRv
);
82 typedef void (Promise::*MaybeFunc
)(JSContext
* aCx
,
83 JS::Handle
<JS::Value
> aValue
);
85 void MaybeResolve(JSContext
* aCx
,
86 JS::Handle
<JS::Value
> aValue
);
87 void MaybeReject(JSContext
* aCx
,
88 JS::Handle
<JS::Value
> aValue
);
90 // Helpers for using Promise from C++.
91 // Most DOM objects are handled already. To add a new type T, add a
92 // ToJSValue overload in ToJSValue.h.
93 // aArg is a const reference so we can pass rvalues like integer constants
95 void MaybeResolve(const T
& aArg
) {
96 MaybeSomething(aArg
, &Promise::MaybeResolve
);
99 inline void MaybeReject(nsresult aArg
) {
100 MOZ_ASSERT(NS_FAILED(aArg
));
101 MaybeSomething(aArg
, &Promise::MaybeReject
);
103 // DO NOT USE MaybeRejectBrokenly with in new code. Promises should be
104 // rejected with Error instances.
105 // Note: MaybeRejectBrokenly is a template so we can use it with DOMError
106 // without instantiating the DOMError specialization of MaybeSomething in
107 // every translation unit that includes this header, because that would
108 // require use to include DOMError.h either here or in all those translation
111 void MaybeRejectBrokenly(const T
& aArg
); // Not implemented by default; see
112 // specializations in the .cpp for
113 // the T values we support.
117 nsIGlobalObject
* GetParentObject() const
123 WrapObject(JSContext
* aCx
) MOZ_OVERRIDE
;
125 static already_AddRefed
<Promise
>
126 Constructor(const GlobalObject
& aGlobal
, PromiseInit
& aInit
,
129 static already_AddRefed
<Promise
>
130 Resolve(const GlobalObject
& aGlobal
,
131 JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
);
133 static already_AddRefed
<Promise
>
134 Resolve(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
135 JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
);
137 static already_AddRefed
<Promise
>
138 Reject(const GlobalObject
& aGlobal
,
139 JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
);
141 static already_AddRefed
<Promise
>
142 Reject(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
143 JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
);
145 already_AddRefed
<Promise
>
146 Then(JSContext
* aCx
, AnyCallback
* aResolveCallback
,
147 AnyCallback
* aRejectCallback
, ErrorResult
& aRv
);
149 already_AddRefed
<Promise
>
150 Catch(JSContext
* aCx
, AnyCallback
* aRejectCallback
, ErrorResult
& aRv
);
152 static already_AddRefed
<Promise
>
153 All(const GlobalObject
& aGlobal
,
154 const Sequence
<JS::Value
>& aIterable
, ErrorResult
& aRv
);
156 static already_AddRefed
<Promise
>
157 Race(const GlobalObject
& aGlobal
,
158 const Sequence
<JS::Value
>& aIterable
, ErrorResult
& aRv
);
160 void AppendNativeHandler(PromiseNativeHandler
* aRunnable
);
163 // Do NOT call this unless you're Promise::Create. I wish we could enforce
164 // that from inside this class too, somehow.
165 explicit Promise(nsIGlobalObject
* aGlobal
);
167 friend class PromiseDebugging
;
175 enum PromiseTaskSync
{
180 void SetState(PromiseState aState
)
182 MOZ_ASSERT(mState
== Pending
);
183 MOZ_ASSERT(aState
!= Pending
);
187 void SetResult(JS::Handle
<JS::Value
> aValue
)
192 // Queue an async task to current main or worker thread.
194 DispatchToMainOrWorkerThread(nsIRunnable
* aRunnable
);
196 // This method processes promise's resolve/reject callbacks with promise's
197 // result. It's executed when the resolver.resolve() or resolver.reject() is
198 // called or when the promise already has a result and new callbacks are
199 // appended by then(), catch() or done().
202 void RunResolveTask(JS::Handle
<JS::Value
> aValue
,
203 Promise::PromiseState aState
,
204 PromiseTaskSync aAsynchronous
);
206 void AppendCallbacks(PromiseCallback
* aResolveCallback
,
207 PromiseCallback
* aRejectCallback
);
209 // If we have been rejected and our mResult is a JS exception,
210 // report it to the error console.
211 // Use MaybeReportRejectedOnce() for actual calls.
212 void MaybeReportRejected();
214 void MaybeReportRejectedOnce() {
215 MaybeReportRejected();
217 mResult
= JS::UndefinedValue();
220 void MaybeResolveInternal(JSContext
* aCx
,
221 JS::Handle
<JS::Value
> aValue
,
222 PromiseTaskSync aSync
= AsyncTask
);
223 void MaybeRejectInternal(JSContext
* aCx
,
224 JS::Handle
<JS::Value
> aValue
,
225 PromiseTaskSync aSync
= AsyncTask
);
227 void ResolveInternal(JSContext
* aCx
,
228 JS::Handle
<JS::Value
> aValue
,
229 PromiseTaskSync aSync
= AsyncTask
);
231 void RejectInternal(JSContext
* aCx
,
232 JS::Handle
<JS::Value
> aValue
,
233 PromiseTaskSync aSync
= AsyncTask
);
235 template <typename T
>
236 void MaybeSomething(T
& aArgument
, MaybeFunc aFunc
) {
237 ThreadsafeAutoJSContext cx
;
238 JSObject
* wrapper
= GetWrapper();
239 MOZ_ASSERT(wrapper
); // We preserved it!
241 JSAutoCompartment
ac(cx
, wrapper
);
242 JS::Rooted
<JS::Value
> val(cx
);
243 if (!ToJSValue(cx
, aArgument
, &val
)) {
248 (this->*aFunc
)(cx
, val
);
251 // Static methods for the PromiseInit functions.
253 JSCallback(JSContext
*aCx
, unsigned aArgc
, JS::Value
*aVp
);
256 ThenableResolverCommon(JSContext
* aCx
, uint32_t /* PromiseCallback::Task */ aTask
,
257 unsigned aArgc
, JS::Value
* aVp
);
259 JSCallbackThenableResolver(JSContext
*aCx
, unsigned aArgc
, JS::Value
*aVp
);
261 JSCallbackThenableRejecter(JSContext
*aCx
, unsigned aArgc
, JS::Value
*aVp
);
264 CreateFunction(JSContext
* aCx
, JSObject
* aParent
, Promise
* aPromise
,
268 CreateThenableFunction(JSContext
* aCx
, Promise
* aPromise
, uint32_t aTask
);
270 void HandleException(JSContext
* aCx
);
272 void RemoveFeature();
274 nsRefPtr
<nsIGlobalObject
> mGlobal
;
276 nsTArray
<nsRefPtr
<PromiseCallback
> > mResolveCallbacks
;
277 nsTArray
<nsRefPtr
<PromiseCallback
> > mRejectCallbacks
;
279 JS::Heap
<JS::Value
> mResult
;
282 bool mHadRejectCallback
;
284 bool mResolvePending
;
286 // If a rejected promise on a worker has no reject callbacks attached, it
287 // needs to know when the worker is shutting down, to report the error on the
288 // console before the worker's context is deleted. This feature is used for
290 nsAutoPtr
<PromiseReportRejectFeature
> mFeature
;
294 } // namespace mozilla
296 #endif // mozilla_dom_Promise_h