Bug 1436076 - Part 2 - Use async/await instead of defer in HUDService;r=nchevobbe draft
authorBrian Grinstead <bgrinstead@mozilla.com>
Wed, 07 Feb 2018 08:22:49 -0800
changeset 752157 09cf233f96d10f7513b33d1d4e7c22a8a0d0b77d
parent 752156 66bda83ec808ab69aa6625c11465c2a1b6e8628e
child 752158 0a6fce76ad93a3859647650c0d8391c3a6c3990a
push id98178
push userbgrinstead@mozilla.com
push dateWed, 07 Feb 2018 16:24:38 +0000
reviewersnchevobbe
bugs1436076
milestone60.0a1
Bug 1436076 - Part 2 - Use async/await instead of defer in HUDService;r=nchevobbe MozReview-Commit-ID: KbLjHa8gUGK
devtools/client/webconsole/hudservice.js
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -4,19 +4,16 @@
 
 "use strict";
 
 var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
 const {extend} = require("devtools/shared/extend");
 var {TargetFactory} = require("devtools/client/framework/target");
 var {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
 var {Tools} = require("devtools/client/definitions");
-const { Task } = require("devtools/shared/task");
-var promise = require("promise");
-const defer = require("devtools/shared/defer");
 var Services = require("Services");
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
 loader.lazyRequireGetter(this, "NewWebConsoleFrame", "devtools/client/webconsole/new-webconsole", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
 loader.lazyRequireGetter(this, "showDoorhanger", "devtools/client/shared/doorhanger", true);
@@ -34,17 +31,17 @@ var gHudId = 0;
 function HUD_SERVICE() {
   this.consoles = new Map();
   this.lastFinishedRequest = { callback: null };
 }
 
 HUD_SERVICE.prototype =
 {
   _browserConsoleID: null,
-  _browserConsoleDefer: null,
+  _browserConsoleInitializing: null,
 
   /**
    * Keeps a reference for each Web Console / Browser Console that is created.
    * @type Map
    */
   consoles: null,
 
   _browerConsoleSessionState: false,
@@ -158,88 +155,87 @@ HUD_SERVICE.prototype =
     let toolbox = gDevTools.getToolbox(target);
     let panel = toolbox ? toolbox.getPanel("webconsole") : null;
     return panel ? panel.hud : null;
   },
 
   /**
    * Toggle the Browser Console.
    */
-  toggleBrowserConsole() {
+  async toggleBrowserConsole() {
     if (this._browserConsoleID) {
       let hud = this.getHudReferenceById(this._browserConsoleID);
       return hud.destroy();
     }
 
-    if (this._browserConsoleDefer) {
-      return this._browserConsoleDefer.promise;
+    if (this._browserConsoleInitializing) {
+      return this._browserConsoleInitializing;
     }
 
-    this._browserConsoleDefer = defer();
-
-    function connect() {
+    async function connect() {
       // Ensure that the root actor and the tab actors have been registered on the
       // DebuggerServer, so that the Browser Console can retrieve the console actors.
       // (See Bug 1416105 for rationale).
       DebuggerServer.init();
       DebuggerServer.registerActors({ root: true, tab: true });
 
       DebuggerServer.allowChromeProcess = true;
 
       let client = new DebuggerClient(DebuggerServer.connectPipe());
-      return client.connect()
-        .then(() => client.getProcess())
-        .then(response => {
-          // Use a TabActor in order to ensure calling `attach` to the ChromeActor
-          return { form: response.form, client, chrome: true, isTabActor: true };
-        });
+      await client.connect();
+      let response = await client.getProcess();
+      return { form: response.form, client, chrome: true, isTabActor: true };
     }
 
-    let target;
-    function getTarget(connection) {
-      return TargetFactory.forRemoteTab(connection);
+    async function openWindow(t) {
+      let browserConsoleURL = Tools.webConsole.browserConsoleURL;
+      let win = Services.ww.openWindow(null, browserConsoleURL, "_blank",
+                                       BC_WINDOW_FEATURES, null);
+      await new Promise(resolve => {
+        win.addEventListener("DOMContentLoaded", resolve, {once: true});
+      });
+
+      win.document.title = l10n.getStr("browserConsole.title");
+
+      if (browserConsoleURL === Tools.webConsole.oldWebConsoleURL) {
+        return {iframeWindow: win, chromeWindow: win};
+      }
+
+      let iframe = win.document.querySelector("iframe");
+      await new Promise(resolve => {
+        iframe.addEventListener("DOMContentLoaded", resolve, {once: true});
+      });
+
+      return {iframeWindow: iframe.contentWindow, chromeWindow: win};
     }
-    function openWindow(t) {
-      target = t;
-      return new Promise(resolve => {
-        let browserConsoleURL = Tools.webConsole.browserConsoleURL;
-        let win = Services.ww.openWindow(null, browserConsoleURL, "_blank",
-                                         BC_WINDOW_FEATURES, null);
-        win.addEventListener("DOMContentLoaded", () => {
-          win.document.title = l10n.getStr("browserConsole.title");
-          if (browserConsoleURL === Tools.webConsole.oldWebConsoleURL) {
-            resolve({iframeWindow: win, chromeWindow: win});
-          } else {
-            win.document.querySelector("iframe").addEventListener("DOMContentLoaded",
-              e => resolve({iframeWindow: e.target.defaultView, chromeWindow: win}),
-              { once: true }
-            );
-          }
-        }, {once: true});
-      });
-    }
-    connect().then(getTarget).then(openWindow).then(({iframeWindow, chromeWindow}) => {
-      return this.openBrowserConsole(target, iframeWindow, chromeWindow)
-        .then(browserConsole => {
-          this._browserConsoleDefer.resolve(browserConsole);
-          this._browserConsoleDefer = null;
-        });
-    }, console.error.bind(console));
 
-    return this._browserConsoleDefer.promise;
+    // Temporarily cache the async startup sequence so that if toggleBrowserConsole
+    // gets called again we can return this console instead of opening another one.
+    this._browserConsoleInitializing = (async () => {
+      let connection = await connect();
+      let target = await TargetFactory.forRemoteTab(connection);
+      let {iframeWindow, chromeWindow} = await openWindow(target);
+      let browserConsole =
+        await this.openBrowserConsole(target, iframeWindow, chromeWindow);
+      return browserConsole;
+    })();
+
+    let browserConsole = await this._browserConsoleInitializing;
+    this._browserConsoleInitializing = null;
+    return browserConsole;
   },
 
   /**
    * Opens or focuses the Browser Console.
    */
   openBrowserConsoleOrFocus() {
     let hud = this.getBrowserConsole();
     if (hud) {
       hud.iframeWindow.focus();
-      return promise.resolve(hud);
+      return Promise.resolve(hud);
     }
 
     return this.toggleBrowserConsole();
   },
 
   /**
    * Get the Browser Console instance, if open.
    *
@@ -534,55 +530,50 @@ WebConsole.prototype = {
 
   /**
    * Destroy the object. Call this method to avoid memory leaks when the Web
    * Console is closed.
    *
    * @return object
    *         A promise object that is resolved once the Web Console is closed.
    */
-  destroy() {
+  async destroy() {
     if (this._destroyer) {
-      return this._destroyer.promise;
+      return this._destroyer;
     }
 
-    HUDService.consoles.delete(this.hudId);
-
-    this._destroyer = defer();
+    this._destroyer = (async () => {
+      HUDService.consoles.delete(this.hudId);
 
-    // The document may already be removed
-    if (this.chromeUtilsWindow && this.mainPopupSet) {
-      let popupset = this.mainPopupSet;
-      let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
-      for (let panel of panels) {
-        panel.hidePopup();
+      // The document may already be removed
+      if (this.chromeUtilsWindow && this.mainPopupSet) {
+        let popupset = this.mainPopupSet;
+        let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
+        for (let panel of panels) {
+          panel.hidePopup();
+        }
       }
-    }
 
-    let onDestroy = Task.async(function* () {
+      if (this.ui) {
+        await this.ui.destroy();
+      }
+
       if (!this._browserConsole) {
         try {
-          yield this.target.activeTab.focus();
+          await this.target.activeTab.focus();
         } catch (ex) {
           // Tab focus can fail if the tab or target is closed.
         }
       }
 
       let id = WebConsoleUtils.supportsString(this.hudId);
       Services.obs.notifyObservers(id, "web-console-destroyed");
-      this._destroyer.resolve(null);
-    }.bind(this));
+    })();
 
-    if (this.ui) {
-      this.ui.destroy().then(onDestroy);
-    } else {
-      onDestroy();
-    }
-
-    return this._destroyer.promise;
+    return this._destroyer;
   },
 };
 
 /**
  * A BrowserConsole instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
  *
@@ -654,32 +645,28 @@ BrowserConsole.prototype = extend(WebCon
   /**
    * Destroy the object.
    *
    * @return object
    *         A promise object that is resolved once the Browser Console is closed.
    */
   destroy() {
     if (this._bcDestroyer) {
-      return this._bcDestroyer.promise;
+      return this._bcDestroyer;
     }
 
-    this._telemetry.toolClosed("browserconsole");
-
-    this._bcDestroyer = defer();
+    this._bcDestroyer = (async () => {
+      this._telemetry.toolClosed("browserconsole");
+      await this.$destroy();
+      await this.target.client.close();
+      HUDService._browserConsoleID = null;
+      this.chromeWindow.close();
+    })();
 
-    let chromeWindow = this.chromeWindow;
-    this.$destroy().then(() =>
-      this.target.client.close().then(() => {
-        HUDService._browserConsoleID = null;
-        chromeWindow.close();
-        this._bcDestroyer.resolve(null);
-      }));
-
-    return this._bcDestroyer.promise;
+    return this._bcDestroyer;
   },
 });
 
 const HUDService = new HUD_SERVICE();
 exports.HUDService = HUDService;
 
 /**
  * The ShutdownObserver listens for app shutdown and saves the current state