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
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_DOMMozPromiseRequestHolder_h
#define mozilla_dom_DOMMozPromiseRequestHolder_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/MozPromise.h"
namespace mozilla::dom {
/**
* This is a helper class that can be used when MozPromises are
* being consumed by binding layer code. It effectively creates
* a MozPromiseRequestHolder that auto-disconnects when the binding's
* global is disconnected.
*
* It can be used like this:
*
* RefPtr<Promise>
* SomeAsyncAPI(Args& aArgs, ErrorResult& aRv)
* {
* nsIGlobalObject* global = GetParentObject();
* if (!global) {
* aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
* return nullptr;
* }
*
* RefPtr<Promise> outer = Promise::Create(global, aRv);
* if (aRv.Failed()) {
* return nullptr;
* }
*
* RefPtr<DOMMozPromiseRequestHolder> holder =
* new DOMMozPromiseRequestHolder(global);
*
* DoAsyncStuff()->Then(
* global->EventTargetFor(TaskCategory::Other), __func__,
* [holder, outer] (const Result& aResult) {
* holder->Complete();
*
* // Note, you can access the holder's bound global in
* // your reaction handler. Its mostly likely set if
* // the handler fires, but you still must check for
* // its existence since something could disconnect
* // the global between when the MozPromise reaction
* // runnable is queued and when it actually runs.
* nsIGlobalObject* global = holder->GetParentObject();
* NS_ENSURE_TRUE_VOID(global);
*
* outer->MaybeResolve(aResult);
* }, [holder, outer] (nsresult aRv) {
* holder->Complete();
* outer->MaybeReject(aRv);
* })->Track(*holder);
*
* return outer.forget();
* }
*
* NOTE: Currently this helper class extends DETH. This is only
* so that it can bind to the global and receive the
* DisconnectFromOwner() method call. In this future the
* binding code should be factored out so DETH is not
* needed here. See bug 1456893.
*/
template <typename PromiseType>
class DOMMozPromiseRequestHolder final : public DOMEventTargetHelper {
MozPromiseRequestHolder<PromiseType> mHolder;
~DOMMozPromiseRequestHolder() = default;
void DisconnectFromOwner() override {
mHolder.DisconnectIfExists();
DOMEventTargetHelper::DisconnectFromOwner();
}
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override {
// We are extending DETH to get notified when the global goes
// away, but this object should never actually be exposed to
// script.
MOZ_CRASH("illegal method");
}
public:
explicit DOMMozPromiseRequestHolder(nsIGlobalObject* aGlobal)
: DOMEventTargetHelper(aGlobal) {
MOZ_DIAGNOSTIC_ASSERT(aGlobal);
}
operator MozPromiseRequestHolder<PromiseType>&() { return mHolder; }
operator const MozPromiseRequestHolder<PromiseType>&() const {
return mHolder;
}
void Complete() { mHolder.Complete(); }
void DisconnectIfExists() { mHolder.DisconnectIfExists(); }
bool Exists() const { return mHolder.Exists(); }
NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMMozPromiseRequestHolder,
DOMEventTargetHelper)
};
} // namespace mozilla::dom
#endif // mozilla_dom_DOMMozPromiseRequestHolder_h
|