Bug 1368202 - convert uses of "defer" to "new Promise" in client/inspector draft
authorNicolas Ouellet-Payeur <nicolaso@google.com>
Thu, 03 Aug 2017 00:28:05 -0700
changeset 620181 26b9cecda3c1e24531467cc3f1dc0a053a998c93
parent 620112 d942ef54fdf726840a698d2ddcaf989d2c00edbc
child 640621 45a73fe73ceefc9410fbbad07884f0f0006cac48
push id71954
push userbmo:nicolaso@google.com
push dateThu, 03 Aug 2017 07:34:56 +0000
bugs1368202
milestone57.0a1
Bug 1368202 - convert uses of "defer" to "new Promise" in client/inspector MozReview-Commit-ID: lXAVyomDlV
devtools/client/inspector/computed/computed.js
devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
devtools/client/inspector/inspector.js
devtools/client/inspector/markup/markup.js
devtools/client/inspector/markup/test/browser_markup_copy_image_data.js
devtools/client/inspector/markup/test/browser_markup_events_form.js
devtools/client/inspector/markup/test/browser_markup_load_01.js
devtools/client/inspector/markup/test/browser_markup_mutation_01.js
devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js
devtools/client/inspector/markup/test/head.js
devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js
devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-03.js
devtools/client/inspector/rules/test/browser_rules_original-source-link.js
devtools/client/inspector/rules/test/browser_rules_original-source-link2.js
devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
devtools/client/inspector/rules/test/doc_frame_script.js
devtools/client/inspector/shared/test/doc_frame_script.js
devtools/client/inspector/shared/test/head.js
devtools/client/inspector/test/browser_inspector_highlighter-hover_01.js
devtools/client/inspector/test/browser_inspector_menu-06-other.js
devtools/client/inspector/test/browser_inspector_startup.js
devtools/client/inspector/test/head.js
devtools/client/inspector/test/shared-head.js
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const ToolDefinitions = require("devtools/client/definitions").Tools;
 const CssLogic = require("devtools/shared/inspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
 const promise = require("promise");
-const defer = require("devtools/shared/defer");
 const Services = require("Services");
 const OutputParser = require("devtools/client/shared/output-parser");
 const {PrefObserver} = require("devtools/client/shared/prefs");
 const {createChild} = require("devtools/client/inspector/shared/utils");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
 const {
   VIEW_NODE_SELECTOR_TYPE,
@@ -397,50 +396,50 @@ CssComputedView.prototype = {
     return {type, value};
   },
 
   _createPropertyViews: function () {
     if (this._createViewsPromise) {
       return this._createViewsPromise;
     }
 
-    let deferred = defer();
-    this._createViewsPromise = deferred.promise;
-
     this.refreshSourceFilter();
     this.numVisibleProperties = 0;
     let fragment = this.styleDocument.createDocumentFragment();
 
-    this._createViewsProcess = new UpdateProcess(
-      this.styleWindow, CssComputedView.propertyNames, {
-        onItem: (propertyName) => {
-          // Per-item callback.
-          let propView = new PropertyView(this, propertyName);
-          fragment.appendChild(propView.buildMain());
-          fragment.appendChild(propView.buildSelectorContainer());
+    this._createViewsPromise = new Promise((resolve, reject) => {
+      this._createViewsProcess = new UpdateProcess(
+        this.styleWindow, CssComputedView.propertyNames, {
+          onItem: (propertyName) => {
+            // Per-item callback.
+            let propView = new PropertyView(this, propertyName);
+            fragment.appendChild(propView.buildMain());
+            fragment.appendChild(propView.buildSelectorContainer());
 
-          if (propView.visible) {
-            this.numVisibleProperties++;
+            if (propView.visible) {
+              this.numVisibleProperties++;
+            }
+            this.propertyViews.push(propView);
+          },
+          onCancel: () => {
+            reject("_createPropertyViews cancelled");
+          },
+          onDone: () => {
+            // Completed callback.
+            this.element.appendChild(fragment);
+            this.noResults.hidden = this.numVisibleProperties > 0;
+            resolve(undefined);
           }
-          this.propertyViews.push(propView);
-        },
-        onCancel: () => {
-          deferred.reject("_createPropertyViews cancelled");
-        },
-        onDone: () => {
-          // Completed callback.
-          this.element.appendChild(fragment);
-          this.noResults.hidden = this.numVisibleProperties > 0;
-          deferred.resolve(undefined);
         }
-      }
-    );
+      );
+    });
 
     this._createViewsProcess.schedule();
-    return deferred.promise;
+
+    return this._createViewsPromise;
   },
 
   /**
    * Refresh the panel content.
    */
   refreshPanel: function () {
     if (!this._viewedElement) {
       return promise.resolve();
@@ -477,45 +476,45 @@ CssComputedView.prototype = {
       this.noResults.hidden = true;
 
       // Reset visible property count
       this.numVisibleProperties = 0;
 
       // Reset zebra striping.
       this._darkStripe = true;
 
-      let deferred = defer();
-      this._refreshProcess = new UpdateProcess(
-        this.styleWindow, this.propertyViews, {
-          onItem: (propView) => {
-            propView.refresh();
-          },
-          onCancel: () => {
-            deferred.reject("_refreshProcess of computed view cancelled");
-          },
-          onDone: () => {
-            this._refreshProcess = null;
-            this.noResults.hidden = this.numVisibleProperties > 0;
+      return new Promise((resolve, reject) => {
+        this._refreshProcess = new UpdateProcess(
+          this.styleWindow, this.propertyViews, {
+            onItem: (propView) => {
+              propView.refresh();
+            },
+            onCancel: () => {
+              reject("_refreshProcess of computed view cancelled");
+            },
+            onDone: () => {
+              this._refreshProcess = null;
+              this.noResults.hidden = this.numVisibleProperties > 0;
 
-            if (this.searchField.value.length > 0 &&
-                !this.numVisibleProperties) {
-              this.searchField.classList
-                              .add("devtools-style-searchbox-no-match");
-            } else {
-              this.searchField.classList
-                              .remove("devtools-style-searchbox-no-match");
+              if (this.searchField.value.length > 0 &&
+                  !this.numVisibleProperties) {
+                this.searchField.classList
+                                .add("devtools-style-searchbox-no-match");
+              } else {
+                this.searchField.classList
+                                .remove("devtools-style-searchbox-no-match");
+              }
+
+              this.inspector.emit("computed-view-refreshed");
+              resolve(undefined);
             }
-
-            this.inspector.emit("computed-view-refreshed");
-            deferred.resolve(undefined);
           }
-        }
-      );
-      this._refreshProcess.schedule();
-      return deferred.promise;
+        );
+        this._refreshProcess.schedule();
+      });
     }).catch((err) => console.error(err));
   },
 
   /**
    * Handle the shortcut events in the computed view.
    */
   _onShortcut: function (name, event) {
     if (!event.target.closest("#sidebar-panel-computedview")) {
@@ -1374,28 +1373,24 @@ SelectorView.prototype = {
       let oldSource = this.source;
       this.source = CssLogic.l10n("rule.sourceElement");
       return promise.resolve(oldSource);
     }
 
     let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
 
     if (showOrig && rule.type !== ELEMENT_STYLE) {
-      let deferred = defer();
-
       // set as this first so we show something while we're fetching
       this.source = CssLogic.shortSource(this.sheet) + ":" + rule.line;
 
-      rule.getOriginalLocation().then(({href, line}) => {
+      return rule.getOriginalLocation().then(({href, line}) => {
         let oldSource = this.source;
         this.source = CssLogic.shortSource({href: href}) + ":" + line;
-        deferred.resolve(oldSource);
+        return oldSource;
       });
-
-      return deferred.promise;
     }
 
     let oldSource = this.source;
     this.source = CssLogic.shortSource(this.sheet) + ":" + rule.line;
     return promise.resolve(oldSource);
   },
 
   /**
--- a/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
+++ b/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
@@ -65,19 +65,17 @@ function* checkToggleKeyBinding(win, key
   info("Collapsing the property");
   EventUtils.synthesizeKey(key, {}, win);
   yield onCollapse;
   is(rulesTable.innerHTML, "", "The property has been collapsed");
 }
 
 function checkHelpLinkKeybinding(view) {
   info("Check that MDN link is opened on \"F1\"");
-  let def = defer();
-
   let propView = getFirstVisiblePropertyView(view);
-  propView.mdnLinkClick = function (event) {
-    ok(true, "Pressing F1 opened the MDN link");
-    def.resolve();
-  };
-
-  EventUtils.synthesizeKey("VK_F1", {}, view.styleWindow);
-  return def.promise;
+  return new Promise(resolve => {
+    propView.mdnLinkClick = function (event) {
+      ok(true, "Pressing F1 opened the MDN link");
+      resolve();
+    };
+    EventUtils.synthesizeKey("VK_F1", {}, view.styleWindow);
+  });
 }
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* global window, BrowserLoader */
 
 "use strict";
 
 var Services = require("Services");
 var promise = require("promise");
-var defer = require("devtools/shared/defer");
 var EventEmitter = require("devtools/shared/event-emitter");
 const {executeSoon} = require("devtools/shared/DevToolsUtils");
 var KeyShortcuts = require("devtools/client/shared/key-shortcuts");
 var {Task} = require("devtools/shared/task");
 const {initCssProperties} = require("devtools/shared/fronts/css-properties");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const Telemetry = require("devtools/client/shared/telemetry");
 
@@ -232,18 +231,16 @@ Inspector.prototype = {
         this._target.actorHasMethod("inspector", "resolveRelativeURL").then(value => {
           this._supportsResolveRelativeURL = value;
         }).catch(e => console.error(e)),
       ]);
     });
   },
 
   _deferredOpen: function (defaultSelection) {
-    let deferred = defer();
-
     this.breadcrumbs = new HTMLBreadcrumbs(this);
 
     this.walker.on("new-root", this.onNewRoot);
 
     this.selection.on("new-node-front", this.onNewSelection);
     this.selection.on("detached-front", this.onDetached);
 
     if (this.target.isLocalTab) {
@@ -273,36 +270,36 @@ Inspector.prototype = {
       this.target.on("thread-resumed", this.updateDebuggerPausedWarning);
       this._toolbox.on("select", this.updateDebuggerPausedWarning);
       this.updateDebuggerPausedWarning();
     }
 
     this._initMarkup();
     this.isReady = false;
 
-    this.once("markuploaded", () => {
-      this.isReady = true;
+    return new Promise(resolve => {
+      this.once("markuploaded", () => {
+        this.isReady = true;
 
-      // All the components are initialized. Let's select a node.
-      if (defaultSelection) {
-        this.selection.setNodeFront(defaultSelection, "inspector-open");
-        this.markup.expandNode(this.selection.nodeFront);
-      }
+        // All the components are initialized. Let's select a node.
+        if (defaultSelection) {
+          this.selection.setNodeFront(defaultSelection, "inspector-open");
+          this.markup.expandNode(this.selection.nodeFront);
+        }
 
-      // And setup the toolbar only now because it may depend on the document.
-      this.setupToolbar();
+        // And setup the toolbar only now because it may depend on the document.
+        this.setupToolbar();
 
-      this.emit("ready");
-      deferred.resolve(this);
+        this.emit("ready");
+        resolve(this);
+      });
+
+      this.setupSearchBox();
+      this.setupSidebar();
     });
-
-    this.setupSearchBox();
-    this.setupSidebar();
-
-    return deferred.promise;
   },
 
   _onBeforeNavigate: function () {
     this._defaultNode = null;
     this.selection.setNodeFront(null);
     this._destroyMarkup();
     this.isDirty = false;
     this._pendingSelection = null;
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -1,17 +1,16 @@
 /* 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";
 
 const promise = require("promise");
 const Services = require("Services");
-const defer = require("devtools/shared/defer");
 const {Task} = require("devtools/shared/task");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const {PluralForm} = require("devtools/shared/plural-form");
 const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
 const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
@@ -448,25 +447,27 @@ MarkupView.prototype = {
       this._briefBoxModelPromise = null;
       this._briefBoxModelTimer = null;
     }
   },
 
   _brieflyShowBoxModel: function (nodeFront) {
     this._clearBriefBoxModelTimer();
     let onShown = this._showBoxModel(nodeFront);
-    this._briefBoxModelPromise = defer();
 
-    this._briefBoxModelTimer = setTimeout(() => {
-      this._hideBoxModel()
-          .then(this._briefBoxModelPromise.resolve,
-                this._briefBoxModelPromise.resolve);
-    }, NEW_SELECTION_HIGHLIGHTER_TIMER);
+    let _resolve;
+    this._briefBoxModelPromise = new Promise(resolve => {
+      _resolve = resolve;
+      this._briefBoxModelTimer = setTimeout(() => {
+        this._hideBoxModel().then(resolve, resolve);
+      }, NEW_SELECTION_HIGHLIGHTER_TIMER);
+    });
+    this._briefBoxModelPromise.resolve = _resolve;
 
-    return promise.all([onShown, this._briefBoxModelPromise.promise]);
+    return promise.all([onShown, this._briefBoxModelPromise]);
   },
 
   /**
    * Get the MarkupContainer object for a given node, or undefined if
    * none exists.
    */
   getContainer: function (node) {
     return this._containers.get(node);
@@ -1349,25 +1350,23 @@ MarkupView.prototype = {
    * @return {Promise} that will resolve when the inner HTML has been updated.
    */
   updateNodeInnerHTML: function (node, newValue, oldValue) {
     let container = this.getContainer(node);
     if (!container) {
       return promise.reject();
     }
 
-    let def = defer();
-
-    container.undo.do(() => {
-      this.walker.setInnerHTML(node, newValue).then(def.resolve, def.reject);
-    }, () => {
-      this.walker.setInnerHTML(node, oldValue);
+    return new Promise((resolve, reject) => {
+      container.undo.do(() => {
+        this.walker.setInnerHTML(node, newValue).then(resolve, reject);
+      }, () => {
+        this.walker.setInnerHTML(node, oldValue);
+      });
     });
-
-    return def.promise;
   },
 
   /**
    * Insert adjacent HTML to any node displayed in the inspector.
    *
    * @param  {NodeFront} node
    *         The reference node.
    * @param  {String} position
@@ -1379,30 +1378,32 @@ MarkupView.prototype = {
    *         been inserted.
    */
   insertAdjacentHTMLToNode: function (node, position, value) {
     let container = this.getContainer(node);
     if (!container) {
       return promise.reject();
     }
 
-    let def = defer();
+    let injectedNodes = [];
 
-    let injectedNodes = [];
-    container.undo.do(() => {
-      // eslint-disable-next-line no-unsanitized/method
-      this.walker.insertAdjacentHTML(node, position, value).then(nodeArray => {
-        injectedNodes = nodeArray.nodes;
-        return nodeArray;
-      }).then(def.resolve, def.reject);
-    }, () => {
-      this.walker.removeNodes(injectedNodes);
+    return new Promise((resolve, reject) => {
+      container.undo.do(() => {
+        // eslint-disable-next-line no-unsanitized/method
+        this.walker
+            .insertAdjacentHTML(node, position, value)
+            .then(nodeArray => {
+              injectedNodes = nodeArray.nodes;
+              return nodeArray;
+            })
+            .then(resolve, reject);
+      }, () => {
+        this.walker.removeNodes(injectedNodes);
+      });
     });
-
-    return def.promise;
   },
 
   /**
    * Open an editor in the UI to allow editing of a node's outerHTML.
    *
    * @param  {NodeFront} node
    *         The NodeFront to edit.
    */
--- a/devtools/client/inspector/markup/test/browser_markup_copy_image_data.js
+++ b/devtools/client/inspector/markup/test/browser_markup_copy_image_data.js
@@ -43,25 +43,23 @@ function* assertCopyImageDataAvailable(i
   let allMenuItems = openContextMenuAndGetAllItems(inspector);
   let item = allMenuItems.find(i => i.id === "node-menu-copyimagedatauri");
 
   ok(item, "The menu item was found in the contextual menu");
   ok(!item.disabled, "The menu item is enabled");
 }
 
 function triggerCopyImageUrlAndWaitForClipboard(expected, inspector) {
-  let def = defer();
-
-  SimpleTest.waitForClipboard(expected, () => {
-    inspector.markup.getContainer(inspector.selection.nodeFront)
-                    .copyImageDataUri();
-  }, () => {
-    ok(true, "The clipboard contains the expected value " +
-             expected.substring(0, 50) + "...");
-    def.resolve();
-  }, () => {
-    ok(false, "The clipboard doesn't contain the expected value " +
-              expected.substring(0, 50) + "...");
-    def.resolve();
+  return new Promise(resolve => {
+    SimpleTest.waitForClipboard(expected, () => {
+      inspector.markup.getContainer(inspector.selection.nodeFront)
+                      .copyImageDataUri();
+    }, () => {
+      ok(true, "The clipboard contains the expected value " +
+               expected.substring(0, 50) + "...");
+      resolve();
+    }, () => {
+      ok(false, "The clipboard doesn't contain the expected value " +
+                expected.substring(0, 50) + "...");
+      resolve();
+    });
   });
-
-  return def.promise;
 }
--- a/devtools/client/inspector/markup/test/browser_markup_events_form.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_form.js
@@ -31,31 +31,29 @@ add_task(function* () {
   let value = nodeFront.getFormProperty("test-property");
   is(value, "test-value", "There must be custom property");
 
   info("Unregistering actor");
   yield unregisterActor(registrar, front);
 });
 
 function registerTestActor(toolbox) {
-  let deferred = defer();
-
   let options = {
     prefix: "eventsFormActor",
     actorClass: "EventsFormActor",
     moduleUrl: TEST_ACTOR_URL,
   };
 
   // Register as a tab actor
   let client = toolbox.target.client;
-  registerTabActor(client, options).then(({registrar, form}) => {
-    // Attach to the registered actor
-    let front = EventsFormFront(client, form);
-    front.attach().then(() => {
-      deferred.resolve({
-        front: front,
-        registrar: registrar,
+  return new Promise(resolve => {
+    registerTabActor(client, options).then(({registrar, form}) => {
+      // Attach to the registered actor
+      let front = EventsFormFront(client, form);
+      front.attach().then(() => {
+        resolve({
+          front: front,
+          registrar: registrar,
+        });
       });
     });
   });
-
-  return deferred.promise;
 }
--- a/devtools/client/inspector/markup/test/browser_markup_load_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_load_01.js
@@ -68,14 +68,14 @@ function* chooseWithInspectElementContex
     type: "contextmenu",
     button: 2
   }, tab.linkedBrowser);
 
   yield EventUtils.synthesizeKey("Q", {});
 }
 
 function waitForLinkedBrowserEvent(tab, event) {
-  let def = defer();
-  tab.linkedBrowser.addEventListener(event, function () {
-    def.resolve();
-  }, {capture: true, once: true});
-  return def.promise;
+  return new Promise(resolve => {
+    tab.linkedBrowser.addEventListener(event, function () {
+      resolve();
+    }, {capture: true, once: true});
+  });
 }
--- a/devtools/client/inspector/markup/test/browser_markup_mutation_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_mutation_01.js
@@ -312,29 +312,30 @@ add_task(function* () {
     info("Starting test: " + desc);
 
     numMutations = numMutations || 1;
 
     info("Executing the test markup mutation");
 
     // If a test expects more than one mutation it may come through in a single
     // event or possibly in multiples.
-    let def = defer();
     let seenMutations = 0;
-    inspector.on("markupmutation", function onmutation(e, mutations) {
-      seenMutations += mutations.length;
-      info("Receieved " + seenMutations +
-           " mutations, expecting at least " + numMutations);
-      if (seenMutations >= numMutations) {
-        inspector.off("markupmutation", onmutation);
-        def.resolve();
-      }
+    let promise = new Promise(resolve => {
+      inspector.on("markupmutation", function onmutation(e, mutations) {
+        seenMutations += mutations.length;
+        info("Receieved " + seenMutations +
+             " mutations, expecting at least " + numMutations);
+        if (seenMutations >= numMutations) {
+          inspector.off("markupmutation", onmutation);
+          resolve();
+        }
+      });
     });
     yield test(testActor, inspector);
-    yield def.promise;
+    yield promise;
 
     info("Expanding all markup-view nodes to make sure new nodes are imported");
     yield inspector.markup.expandAll();
 
     info("Checking the markup-view content");
     yield check(inspector);
   }
 });
--- a/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js
@@ -121,22 +121,23 @@ function* runTestData(inspector, testAct
                       {selector, before, changeStyle, after}) {
   info("Getting the " + selector + " test node");
   let nodeFront = yield getNodeFront(selector, inspector);
   let container = getContainerForNodeFront(nodeFront, inspector);
   is(!container.elt.classList.contains("not-displayed"), before,
     "The container is marked as " + (before ? "shown" : "hidden"));
 
   info("Listening for the display-change event");
-  let onDisplayChanged = defer();
-  inspector.markup.walker.once("display-change", onDisplayChanged.resolve);
+  let onDisplayChanged = new Promise(resolve => {
+    inspector.markup.walker.once("display-change", resolve);
+  });
 
   info("Making style changes");
   yield changeStyle(testActor);
-  let nodes = yield onDisplayChanged.promise;
+  let nodes = yield onDisplayChanged;
 
   info("Verifying that the list of changed nodes include our container");
 
   ok(nodes.length, "The display-change event was received with a nodes");
   let foundContainer = false;
   for (let node of nodes) {
     if (getContainerForNodeFront(node, inspector) === container) {
       foundContainer = true;
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -1,8 +1,9 @@
+
 /* 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/. */
 /* eslint no-unused-vars: [2, {"vars": "local"}] */
 /* import-globals-from ../../test/head.js */
 "use strict";
 
 // Import the inspector's head.js first (which itself imports shared-head.js).
@@ -121,21 +122,21 @@ function* getFirstChildNodeValue(selecto
  * children updates to be handled.
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  * @return a promise that resolves when all queued children updates have been
  * handled
  */
 function waitForChildrenUpdated({markup}) {
   info("Waiting for queued children updates to be handled");
-  let def = defer();
-  markup._waitForChildren().then(() => {
-    executeSoon(def.resolve);
+  return new Promise(resolve => {
+    markup._waitForChildren().then(() => {
+      executeSoon(resolve);
+    });
   });
-  return def.promise;
 }
 
 /**
  * Simulate a click on the markup-container (a line in the markup-view)
  * that corresponds to the selector passed.
  * @param {String|NodeFront} selector
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
@@ -348,19 +349,19 @@ function* (nodeFront, inspector, assert 
          !pasteHTMLMenuItem.disabled;
 });
 
 /**
  * Wait for all current promises to be resolved. See this as executeSoon that
  * can be used with yield.
  */
 function promiseNextTick() {
-  let deferred = defer();
-  executeSoon(deferred.resolve);
-  return deferred.promise;
+  return new Promise(resolve => {
+    executeSoon(resolve);
+  });
 }
 
 /**
  * Collapses the current text selection in an input field and tabs to the next
  * field.
  */
 function collapseSelectionAndTab(inspector) {
   // collapse selection and move caret to end
--- a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js
@@ -68,26 +68,31 @@ add_task(function* () {
  * @param state {boolean} Desired value of the pref.
  *
  * Note that if the pref already has the value in `state`,
  * then the prefObserver will not trigger. So you should only
  * call this function if you know the pref's current value is
  * not `state`.
  */
 function* setBooleanPref(pref, state) {
-  let oncePrefChanged = defer();
   let prefObserver = new PrefObserver("devtools.");
-  prefObserver.on(pref, oncePrefChanged.resolve);
+  let oncePrefChanged = new Promise(resolve => {
+    prefObserver.on(pref, onPrefChanged);
+
+    function onPrefChanged() {
+      prefObserver.off(pref, onPrefChanged);
+      resolve();
+    }
+  });
 
   info("Set the pref " + pref + " to: " + state);
   Services.prefs.setBoolPref(pref, state);
 
   info("Wait for prefObserver to call back so the UI can update");
-  yield oncePrefChanged.promise;
-  prefObserver.off(pref, oncePrefChanged.resolve);
+  yield oncePrefChanged;
 }
 
 /**
  * Tests that the MDN context menu item is shown when it should be,
  * and hidden when it should be.
  *   - iterate through every node in the rule view
  *   - set that node as popupNode (the node that the context menu
  *   is shown for)
--- a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-03.js
@@ -72,26 +72,31 @@ add_task(function* () {
  * @param state {boolean} Desired value of the pref.
  *
  * Note that if the pref already has the value in `state`,
  * then the prefObserver will not trigger. So you should only
  * call this function if you know the pref's current value is
  * not `state`.
  */
 function* setBooleanPref(pref, state) {
-  let oncePrefChanged = defer();
   let prefObserver = new PrefObserver("devtools.");
-  prefObserver.on(pref, oncePrefChanged.resolve);
+  let oncePrefChanged = new Promise(resolve => {
+    prefObserver.on(pref, onPrefChanged);
+
+    function onPrefChanged() {
+      prefObserver.off(pref, onPrefChanged);
+      resolve();
+    }
+  });
 
   info("Set the pref " + pref + " to: " + state);
   Services.prefs.setBoolPref(pref, state);
 
   info("Wait for prefObserver to call back so the UI can update");
-  yield oncePrefChanged.promise;
-  prefObserver.off(pref, oncePrefChanged.resolve);
+  yield oncePrefChanged;
 }
 
 /**
  * Test whether the MDN tooltip context menu item is visible when it should be.
  *
  * @param view The rule view
  * @param shouldBeVisible {boolean} Whether we expect the context
  * menu item to be visible or not.
--- a/devtools/client/inspector/rules/test/browser_rules_original-source-link.js
+++ b/devtools/client/inspector/rules/test/browser_rules_original-source-link.js
@@ -45,30 +45,28 @@ function* testClickingLink(toolbox, view
   info("Finding the stylesheet link and clicking it");
   let link = getRuleViewLinkByIndex(view, 1);
   link.scrollIntoView();
   link.click();
   yield onStyleEditorReady;
 }
 
 function checkDisplayedStylesheet(toolbox) {
-  let def = defer();
-
   let panel = toolbox.getCurrentPanel();
-  panel.UI.on("editor-selected", (event, editor) => {
-    // The style editor selects the first sheet at first load before
-    // selecting the desired sheet.
-    if (editor.styleSheet.href.endsWith("scss")) {
-      info("Original source editor selected");
-      editor.getSourceEditor().then(editorSelected)
-        .then(def.resolve, def.reject);
-    }
+  return new Promise((resolve, reject) => {
+    panel.UI.on("editor-selected", (event, editor) => {
+      // The style editor selects the first sheet at first load before
+      // selecting the desired sheet.
+      if (editor.styleSheet.href.endsWith("scss")) {
+        info("Original source editor selected");
+        editor.getSourceEditor().then(editorSelected)
+          .then(resolve, reject);
+      }
+    });
   });
-
-  return def.promise;
 }
 
 function editorSelected(editor) {
   let href = editor.styleSheet.href;
   ok(href.endsWith("doc_sourcemaps.scss"),
     "selected stylesheet is correct one");
 
   let {line} = editor.sourceEditor.getCursor();
--- a/devtools/client/inspector/rules/test/browser_rules_original-source-link2.js
+++ b/devtools/client/inspector/rules/test/browser_rules_original-source-link2.js
@@ -45,30 +45,28 @@ function* testClickingLink(toolbox, view
   info("Finding the stylesheet link and clicking it");
   let link = getRuleViewLinkByIndex(view, 1);
   link.scrollIntoView();
   link.click();
   yield onStyleEditorReady;
 }
 
 function checkDisplayedStylesheet(toolbox) {
-  let def = defer();
-
   let panel = toolbox.getCurrentPanel();
-  panel.UI.on("editor-selected", (event, editor) => {
-    // The style editor selects the first sheet at first load before
-    // selecting the desired sheet.
-    if (editor.styleSheet.href.endsWith("scss")) {
-      info("Original source editor selected");
-      editor.getSourceEditor().then(editorSelected)
-        .then(def.resolve, def.reject);
-    }
+  return new Promise((resolve, reject) => {
+    panel.UI.on("editor-selected", (event, editor) => {
+      // The style editor selects the first sheet at first load before
+      // selecting the desired sheet.
+      if (editor.styleSheet.href.endsWith("scss")) {
+        info("Original source editor selected");
+        editor.getSourceEditor().then(editorSelected)
+          .then(resolve, reject);
+      }
+    });
   });
-
-  return def.promise;
 }
 
 function editorSelected(editor) {
   let href = editor.styleSheet.href;
   ok(href.endsWith("doc_sourcemaps.scss"),
     "selected stylesheet is correct one");
 
   let {line} = editor.sourceEditor.getCursor();
--- a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
@@ -81,22 +81,27 @@ add_task(function* () {
   Services.prefs.clearUserPref(PREF_UA_STYLES);
 });
 
 function* setUserAgentStylesPref(val) {
   info("Setting the pref " + PREF_UA_STYLES + " to: " + val);
 
   // Reset the pref and wait for PrefObserver to callback so UI
   // has a chance to get updated.
-  let oncePrefChanged = defer();
   let prefObserver = new PrefObserver("devtools.");
-  prefObserver.on(PREF_UA_STYLES, oncePrefChanged.resolve);
+  let oncePrefChanged = new Promise(resolve => {
+    prefObserver.on(PREF_UA_STYLES, onPrefChanged);
+
+    function onPrefChanged() {
+      prefObserver.off(PREF_UA_STYLES, onPrefChanged);
+      resolve();
+    }
+  });
   Services.prefs.setBoolPref(PREF_UA_STYLES, val);
-  yield oncePrefChanged.promise;
-  prefObserver.off(PREF_UA_STYLES, oncePrefChanged.resolve);
+  yield oncePrefChanged;
 }
 
 function* userAgentStylesVisible(inspector, view) {
   info("Making sure that user agent styles are currently visible");
 
   let userRules;
   let uaRules;
 
--- a/devtools/client/inspector/rules/test/doc_frame_script.js
+++ b/devtools/client/inspector/rules/test/doc_frame_script.js
@@ -11,21 +11,16 @@
 // then execute code upon receiving, and immediately send back a message.
 // This is so that chrome test code can execute code in content and wait for a
 // response this way:
 // let response = yield executeInContent(browser, "Test:msgName", data, true);
 // The response message should have the same name "Test:msgName"
 //
 // Some listeners do not send a response message back.
 
-var {utils: Cu} = Components;
-
-var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
-var defer = require("devtools/shared/defer");
-
 /**
  * Get a value for a given property name in a css rule in a stylesheet, given
  * their indexes
  * @param {Object} data Expects a data object with the following properties
  * - {Number} styleSheetIndex
  * - {Number} ruleIndex
  * - {String} name
  * @return {String} The value, if found, null otherwise
@@ -93,21 +88,19 @@ var dumpn = msg => dump(msg + "\n");
  *
  * @param {Function} validatorFn A validator function that returns a boolean.
  * This is called every few milliseconds to check if the result is true. When
  * it is true, the promise resolves.
  * @return a promise that resolves when the function returned true or rejects
  * if the timeout is reached
  */
 function waitForSuccess(validatorFn) {
-  let def = defer();
-
-  function wait(fn) {
-    if (fn()) {
-      def.resolve();
-    } else {
-      setTimeout(() => wait(fn), 200);
+  return new Promise(resolve => {
+    function wait(fn) {
+      if (fn()) {
+        resolve();
+      } else {
+        setTimeout(() => wait(fn), 200);
+      }
     }
-  }
-  wait(validatorFn);
-
-  return def.promise;
+    wait(validatorFn);
+  });
 }
--- a/devtools/client/inspector/shared/test/doc_frame_script.js
+++ b/devtools/client/inspector/shared/test/doc_frame_script.js
@@ -11,20 +11,16 @@
 // then execute code upon receiving, and immediately send back a message.
 // This is so that chrome test code can execute code in content and wait for a
 // response this way:
 // let response = yield executeInContent(browser, "Test:MsgName", data, true);
 // The response message should have the same name "Test:MsgName"
 //
 // Some listeners do not send a response message back.
 
-var {utils: Cu} = Components;
-var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
-var defer = require("devtools/shared/defer");
-
 /**
  * Get a value for a given property name in a css rule in a stylesheet, given
  * their indexes
  * @param {Object} data Expects a data object with the following properties
  * - {Number} styleSheetIndex
  * - {Number} ruleIndex
  * - {String} name
  * @return {String} The value, if found, null otherwise
@@ -95,21 +91,19 @@ var dumpn = msg => dump(msg + "\n");
  * This is called every few milliseconds to check if the result is true. When
  * it is true, the promise resolves.
  * @param {String} name Optional name of the test. This is used to generate
  * the success and failure messages.
  * @return a promise that resolves when the function returned true or rejects
  * if the timeout is reached
  */
 function waitForSuccess(validatorFn, name = "untitled") {
-  let def = defer();
-
-  function wait(fn) {
-    if (fn()) {
-      def.resolve();
-    } else {
-      setTimeout(() => wait(fn), 200);
+  return new Promise(resolve => {
+    function wait(fn) {
+      if (fn()) {
+        resolve();
+      } else {
+        setTimeout(() => wait(fn), 200);
+      }
     }
-  }
-  wait(validatorFn);
-
-  return def.promise;
+    wait(validatorFn);
+  });
 }
--- a/devtools/client/inspector/shared/test/head.js
+++ b/devtools/client/inspector/shared/test/head.js
@@ -97,29 +97,27 @@ addTab = function (url) {
  *        When it is true, the promise resolves.
  * @param {String} name
  *        Optional name of the test. This is used to generate
  *        the success and failure messages.
  * @return a promise that resolves when the function returned true or rejects
  * if the timeout is reached
  */
 function waitForSuccess(validatorFn, name = "untitled") {
-  let def = defer();
-
-  function wait(validator) {
-    if (validator()) {
-      ok(true, "Validator function " + name + " returned true");
-      def.resolve();
-    } else {
-      setTimeout(() => wait(validator), 200);
+  return new Promise(resolve => {
+    function wait(validator) {
+      if (validator()) {
+        ok(true, "Validator function " + name + " returned true");
+        resolve();
+      } else {
+        setTimeout(() => wait(validator), 200);
+      }
     }
-  }
-  wait(validatorFn);
-
-  return def.promise;
+    wait(validatorFn);
+  });
 }
 
 /**
  * Get the dataURL for the font family tooltip.
  *
  * @param {String} font
  *        The font family value.
  * @param {object} nodeFront
--- a/devtools/client/inspector/test/browser_inspector_highlighter-hover_01.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-hover_01.js
@@ -28,14 +28,14 @@ add_task(function* () {
   yield waitForTheBrieflyShowBoxModelTimeout();
 
   yield testActor.setProperty("p", "textContent", "dary!!!!");
   isVisible = yield testActor.isHighlighting();
   ok(isVisible, "the highlighter is still visible");
 });
 
 function waitForTheBrieflyShowBoxModelTimeout() {
-  let deferred = defer();
   // Note that the current timeout is 1 sec and is neither configurable nor
   // exported anywhere we can access, so hard-coding the timeout
-  setTimeout(deferred.resolve, 1500);
-  return deferred.promise;
+  return new Promise(resolve => {
+    setTimeout(resolve, 1500);
+  });
 }
--- a/devtools/client/inspector/test/browser_inspector_menu-06-other.js
+++ b/devtools/client/inspector/test/browser_inspector_menu-06-other.js
@@ -75,19 +75,19 @@ add_task(function* () {
   function* testDeleteRootNode() {
     info("Testing 'Delete Node' menu item does not delete root node.");
     yield selectNode("html", inspector);
 
     let allMenuItems = openContextMenuAndGetAllItems(inspector);
     let deleteNode = allMenuItems.find(item => item.id === "node-menu-delete");
     deleteNode.click();
 
-    let deferred = defer();
-    executeSoon(deferred.resolve);
-    yield deferred.promise;
+    yield new Promise(resolve => {
+      executeSoon(resolve);
+    });
 
     ok((yield testActor.eval("!!content.document.documentElement")),
        "Document element still alive.");
   }
 
   function* testScrollIntoView() {
     // Follow up bug to add this test - https://bugzilla.mozilla.org/show_bug.cgi?id=1154107
     todo(false, "Verify that node is scrolled into the viewport.");
--- a/devtools/client/inspector/test/browser_inspector_startup.js
+++ b/devtools/client/inspector/test/browser_inspector_startup.js
@@ -64,20 +64,20 @@ add_task(function* () {
   response.finish();
 
   // We should then receive the page load event
   info("Wait for load");
   yield pageLoaded;
 });
 
 function waitForLinkedBrowserEvent(tab, event) {
-  let def = defer();
-  tab.linkedBrowser.addEventListener(event, function () {
-    def.resolve();
-  }, {capture: true, once: true});
-  return def.promise;
+  return new Promise(resolve => {
+    tab.linkedBrowser.addEventListener(event, function () {
+      resolve();
+    }, {capture: true, once: true});
+  });
 }
 
 function contentReadyState(tab) {
   return ContentTask.spawn(tab.linkedBrowser, null, function () {
     return content.document.readyState;
   });
 }
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -294,26 +294,26 @@ var clickContainer = Task.async(function
 /**
  * Simulate the mouse leaving the markup-view area
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  * @return a promise when done
  */
 function mouseLeaveMarkupView(inspector) {
   info("Leaving the markup-view area");
-  let def = defer();
 
   // Find another element to mouseover over in order to leave the markup-view
   let btn = inspector.toolbox.doc.querySelector("#toolbox-controls");
 
   EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"},
     inspector.toolbox.win);
-  executeSoon(def.resolve);
 
-  return def.promise;
+  return new Promise(resolve => {
+    executeSoon(resolve);
+  });
 }
 
 /**
  * Dispatch the copy event on the given element
  */
 function fireCopyEvent(element) {
   let evt = element.ownerDocument.createEvent("Event");
   evt.initEvent("copy", true, true);
@@ -542,72 +542,71 @@ function* waitForMultipleChildrenUpdates
  * children updates to be handled.
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  * @return a promise that resolves when all queued children updates have been
  * handled
  */
 function waitForChildrenUpdated({markup}) {
   info("Waiting for queued children updates to be handled");
-  let def = defer();
-  markup._waitForChildren().then(() => {
-    executeSoon(def.resolve);
+  return new Promise(resolve => {
+    markup._waitForChildren().then(() => {
+      executeSoon(resolve);
+    });
   });
-  return def.promise;
 }
 
 /**
  * Wait for the toolbox to emit the styleeditor-selected event and when done
  * wait for the stylesheet identified by href to be loaded in the stylesheet
  * editor
  *
  * @param {Toolbox} toolbox
  * @param {String} href
  *        Optional, if not provided, wait for the first editor to be ready
  * @return a promise that resolves to the editor when the stylesheet editor is
  * ready
  */
 function waitForStyleEditor(toolbox, href) {
-  let def = defer();
+  info("Waiting for the toolbox to switch to the styleeditor");
 
-  info("Waiting for the toolbox to switch to the styleeditor");
-  toolbox.once("styleeditor-selected").then(() => {
-    let panel = toolbox.getCurrentPanel();
-    ok(panel && panel.UI, "Styleeditor panel switched to front");
+  return new Promise(resolve => {
+    toolbox.once("styleeditor-selected").then(() => {
+      let panel = toolbox.getCurrentPanel();
+      ok(panel && panel.UI, "Styleeditor panel switched to front");
 
-    // A helper that resolves the promise once it receives an editor that
-    // matches the expected href. Returns false if the editor was not correct.
-    let gotEditor = (event, editor) => {
-      let currentHref = editor.styleSheet.href;
-      if (!href || (href && currentHref.endsWith(href))) {
-        info("Stylesheet editor selected");
-        panel.UI.off("editor-selected", gotEditor);
+      // A helper that resolves the promise once it receives an editor that
+      // matches the expected href. Returns false if the editor was not correct.
+      let gotEditor = (event, editor) => {
+        let currentHref = editor.styleSheet.href;
+        if (!href || (href && currentHref.endsWith(href))) {
+          info("Stylesheet editor selected");
+          panel.UI.off("editor-selected", gotEditor);
 
-        editor.getSourceEditor().then(sourceEditor => {
-          info("Stylesheet editor fully loaded");
-          def.resolve(sourceEditor);
-        });
+          editor.getSourceEditor().then(sourceEditor => {
+            info("Stylesheet editor fully loaded");
+            resolve(sourceEditor);
+          });
 
-        return true;
-      }
+          return true;
+        }
 
-      info("The editor was incorrect. Waiting for editor-selected event.");
-      return false;
-    };
+        info("The editor was incorrect. Waiting for editor-selected event.");
+        return false;
+      };
 
-    // The expected editor may already be selected. Check the if the currently
-    // selected editor is the expected one and if not wait for an
-    // editor-selected event.
-    if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
-      // The expected editor is not selected (yet). Wait for it.
-      panel.UI.on("editor-selected", gotEditor);
-    }
+      // The expected editor may already be selected. Check the if the currently
+      // selected editor is the expected one and if not wait for an
+      // editor-selected event.
+      if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
+        // The expected editor is not selected (yet). Wait for it.
+        panel.UI.on("editor-selected", gotEditor);
+      }
+    });
   });
-
-  return def.promise;
 }
 
 /**
  * Checks if document's active element is within the given element.
  * @param  {HTMLDocument}  doc document with active element in question
  * @param  {DOMNode}       container element tested on focus containment
  * @return {Boolean}
  */
--- a/devtools/client/inspector/test/shared-head.js
+++ b/devtools/client/inspector/test/shared-head.js
@@ -236,22 +236,22 @@ function manualDebounce() {
  * @return {Promise} A promise that resolves to the response data when the
  * message has been received
  */
 function waitForContentMessage(name) {
   info("Expecting message " + name + " from content");
 
   let mm = gBrowser.selectedBrowser.messageManager;
 
-  let def = defer();
-  mm.addMessageListener(name, function onMessage(msg) {
-    mm.removeMessageListener(name, onMessage);
-    def.resolve(msg.data);
+  return new Promise(resolve => {
+    mm.addMessageListener(name, function onMessage(msg) {
+      mm.removeMessageListener(name, onMessage);
+      resolve(msg.data);
+    });
   });
-  return def.promise;
 }
 
 /**
  * Send an async message to the frame script (chrome -> content) and wait for a
  * response message with the same name (content -> chrome).
  *
  * @param {String} name
  *        The message name. Should be one of the messages defined