Bug 1454373 - Switch protocol.js to native promises. r=jryans draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Fri, 13 Apr 2018 14:34:12 -0700
changeset 784161 75a6ca87afcbc9a02cee6b9305142ddb2f0a76ac
parent 783377 8c1e0809e25914621647f39ea53aa9cbcec22dc5
push id106870
push userbmo:poirot.alex@gmail.com
push dateWed, 18 Apr 2018 08:06:41 +0000
reviewersjryans
bugs1454373
milestone61.0a1
Bug 1454373 - Switch protocol.js to native promises. r=jryans MozReview-Commit-ID: ALifNayHJJG
devtools/server/tests/unit/test_protocol_stack.js
devtools/shared/defer.js
devtools/shared/protocol.js
--- a/devtools/server/tests/unit/test_protocol_stack.js
+++ b/devtools/server/tests/unit/test_protocol_stack.js
@@ -71,17 +71,17 @@ function run_test() {
 
   client.connect().then(function onConnect() {
     rootClient = RootFront(client);
 
     rootClient.simpleReturn().then(() => {
       let stack = Components.stack;
       while (stack) {
         info(stack.name);
-        if (stack.name == "onConnect") {
+        if (stack.name.includes("run_test/onConnect")) {
           // Reached back to outer function before request
           ok(true, "Complete stack");
           return;
         }
         stack = stack.asyncCaller || stack.caller;
       }
       ok(false, "Incomplete stack");
     }, () => {
--- a/devtools/shared/defer.js
+++ b/devtools/shared/defer.js
@@ -1,15 +1,17 @@
 /* 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/. */
 
 "use strict";
 
-// See bug 1273941 to understand this choice of promise.
+// We have to keep using Promise.jsm here, because DOM Promises
+// start freezing during panel iframes destruction.
+// More info in bug 1454373 comment 15.
 const Promise = require("promise");
 
 /**
  * Returns a deferred object, with a resolve and reject property.
  * https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred
  */
 module.exports = function defer() {
   let resolve, reject;
--- a/devtools/shared/protocol.js
+++ b/devtools/shared/protocol.js
@@ -1,22 +1,35 @@
 /* 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/. */
 
 "use strict";
 
-var promise = require("promise");
-var defer = require("devtools/shared/defer");
 const { extend } = require("devtools/shared/extend");
 var EventEmitter = require("devtools/shared/event-emitter");
 var {getStack, callFunctionWithAsyncStack} = require("devtools/shared/platform/stack");
 var {settleAll} = require("devtools/shared/DevToolsUtils");
 var {lazyLoadSpec, lazyLoadFront} = require("devtools/shared/specs/index");
 
+// Bug 1454373: devtools/shared/defer still uses Promise.jsm which is slower
+// than DOM Promises. So implement our own copy of `defer` based on DOM Promises.
+function defer() {
+  let resolve, reject;
+  let promise = new Promise(function() {
+    resolve = arguments[0];
+    reject = arguments[1];
+  });
+  return {
+    resolve: resolve,
+    reject: reject,
+    promise: promise
+  };
+}
+
 /**
  * Types: named marshallers/demarshallers.
  *
  * Types provide a 'write' function that takes a js representation and
  * returns a protocol representation, and a "read" function that
  * takes a protocol representation and returns a js representation.
  *
  * The read and write methods are also passed a context object that
@@ -978,17 +991,17 @@ Actor.prototype = extend(Pool.prototype,
     this.conn.send({
       from: this.actorID,
       error: error.error || "unknownError",
       message: error.message
     });
   },
 
   _queueResponse: function(create) {
-    let pending = this._pendingResponse || promise.resolve(null);
+    let pending = this._pendingResponse || Promise.resolve(null);
     let response = create(pending);
     this._pendingResponse = response;
   }
 });
 exports.Actor = Actor;
 
 /**
  * Tags a prtotype method as an actor method implementation.
@@ -1247,17 +1260,17 @@ Front.prototype = extend(Pool.prototype,
     return Pool.prototype.manage.call(this, front);
   },
 
   /**
    * @returns a promise that will resolve to the actorID this front
    * represents.
    */
   actor: function() {
-    return promise.resolve(this.actorID);
+    return Promise.resolve(this.actorID);
   },
 
   toString: function() {
     return "[Front for " + this.typeName + "/" + this.actorID + "]";
   },
 
   /**
    * Update the actor from its representation.
@@ -1313,17 +1326,17 @@ Front.prototype = extend(Pool.prototype,
         throw ex;
       }
       if (event.pre) {
         let results = event.pre.map(pre => pre.apply(this, args));
 
         // Check to see if any of the preEvents returned a promise -- if so,
         // wait for their resolution before emitting. Otherwise, emit synchronously.
         if (results.some(result => result && typeof result.then === "function")) {
-          promise.all(results).then(() => {
+          Promise.all(results).then(() => {
             return EventEmitter.emit.apply(null, [this, event.name].concat(args));
           });
           return;
         }
       }
 
       EventEmitter.emit.apply(null, [this, event.name].concat(args));
       return;