Bug 1304941 - reject update promise in BrowserTabActor destroy;r=jryans a=gchang
authorJulian Descottes <jdescottes@mozilla.com>
Fri, 10 Feb 2017 23:43:37 +0100
changeset 376311 df611c3e7160259bd1dbed3363e7d0b3e6ed34b4
parent 376310 fd1161d3089e8f8fcdab7e9081de268dcb9b2f4b
child 376312 3f72efd1474491040d25ea4a170bd1667536f863
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans, gchang
bugs1304941
milestone53.0a2
Bug 1304941 - reject update promise in BrowserTabActor destroy;r=jryans a=gchang MozReview-Commit-ID: LNclCPv1Zo
devtools/server/actors/webbrowser.js
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -278,28 +278,39 @@ BrowserTabList.prototype.getList = funct
   for (let browser of this._getBrowsers()) {
     let selected = browser === selectedBrowser;
     actorPromises.push(
       this._getActorForBrowser(browser)
           .then(actor => {
             // Set the 'selected' properties on all actors correctly.
             actor.selected = selected;
             return actor;
+          }, e => {
+            if (e.error === "tabDestroyed") {
+              // Return null if a tab was destroyed while retrieving the tab list.
+              return null;
+            }
+
+            // Forward unexpected errors.
+            throw e;
           })
     );
   }
 
   if (this._testing && initialMapSize !== this._foundCount) {
     throw new Error("_actorByBrowser map contained actors for dead tabs");
   }
 
   this._mustNotify = true;
   this._checkListening();
 
-  return promise.all(actorPromises);
+  return promise.all(actorPromises).then(values => {
+    // Filter out null values if we received a tabDestroyed error.
+    return values.filter(value => value != null);
+  });
 };
 
 BrowserTabList.prototype._getActorForBrowser = function (browser) {
   // Do we have an existing actor for this browser? If not, create one.
   let actor = this._actorByBrowser.get(browser);
   if (actor) {
     this._foundCount++;
     return actor.update();
@@ -689,16 +700,23 @@ function BrowserTabActor(connection, bro
   this._conn = connection;
   this._browser = browser;
   this._form = null;
 }
 
 BrowserTabActor.prototype = {
   connect() {
     let onDestroy = () => {
+      if (this._deferredUpdate) {
+        // Reject the update promise if the tab was destroyed while requesting an update
+        this._deferredUpdate.reject({
+          error: "tabDestroyed",
+          message: "Tab destroyed while performing a BrowserTabActor update"
+        });
+      }
       this._form = null;
     };
     let connect = DebuggerServer.connectToChild(this._conn, this._browser, onDestroy);
     return connect.then(form => {
       this._form = form;
       return this;
     });
   },
@@ -717,29 +735,29 @@ BrowserTabActor.prototype = {
            this._browser.frameLoader.messageManager;
   },
 
   update() {
     // If the child happens to be crashed/close/detach, it won't have _form set,
     // so only request form update if some code is still listening on the other
     // side.
     if (this._form) {
-      let deferred = promise.defer();
+      this._deferredUpdate = promise.defer();
       let onFormUpdate = msg => {
         // There may be more than just one childtab.js up and running
         if (this._form.actor != msg.json.actor) {
           return;
         }
         this._mm.removeMessageListener("debug:form", onFormUpdate);
         this._form = msg.json;
-        deferred.resolve(this);
+        this._deferredUpdate.resolve(this);
       };
       this._mm.addMessageListener("debug:form", onFormUpdate);
       this._mm.sendAsyncMessage("debug:form");
-      return deferred.promise;
+      return this._deferredUpdate.promise;
     }
 
     return this.connect();
   },
 
   /**
    * If we don't have a title from the content side because it's a zombie tab, try to find
    * it on the chrome side.