Bug 1457187 P1 Add a DOMMozPromiseRequestHolder helper class to auto-disconnect MozPromise Thenables when the global dies. r=baku
authorBen Kelly <ben@wanderview.com>
Thu, 26 Apr 2018 09:18:01 -0700
changeset 460793 184cbe8d02d950ffd9b678f0349c796f2e9170f9
parent 460792 f1c7ad9294b3c200d66590f0e7ddd8cf0c47f0cf
child 460794 4446fa7a754f1283e4a26124a507b648ec0e0a01
push id165
push userfmarier@mozilla.com
push dateMon, 30 Apr 2018 23:50:51 +0000
reviewersbaku
bugs1457187
milestone61.0a1
Bug 1457187 P1 Add a DOMMozPromiseRequestHolder helper class to auto-disconnect MozPromise Thenables when the global dies. r=baku
dom/base/DOMMozPromiseRequestHolder.h
dom/base/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMMozPromiseRequestHolder.h
@@ -0,0 +1,125 @@
+/* -*- 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 {
+namespace 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();
+ *          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();
+    DisconnectFromOwner();
+  }
+
+  void
+  DisconnectIfExists()
+  {
+    mHolder.DisconnectIfExists();
+  }
+
+  bool
+  Exists() const
+  {
+    return mHolder.Exists();
+  }
+
+  NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMMozPromiseRequestHolder, DOMEventTargetHelper)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DOMMozPromiseRequestHolder_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -164,16 +164,17 @@ EXPORTS.mozilla.dom += [
     'DocumentFragment.h',
     'DocumentOrShadowRoot.h',
     'DocumentType.h',
     'DOMError.h',
     'DOMException.h',
     'DOMImplementation.h',
     'DOMIntersectionObserver.h',
     'DOMMatrix.h',
+    'DOMMozPromiseRequestHolder.h',
     'DOMParser.h',
     'DOMPoint.h',
     'DOMPrefs.h',
     'DOMPrefsInternal.h',
     'DOMQuad.h',
     'DOMRect.h',
     'DOMRequest.h',
     'DOMStringList.h',