Bug 1273941 - replace uses of promise.defer in devtools/client/framework; r?jryans draft
authorTom Tromey <tom@tromey.com>
Thu, 09 Jun 2016 09:04:58 -0600
changeset 380906 214d46107946ac01d33ca3956646ca7c74a69277
parent 380905 eb279cfe804e8d1345c07bb7f05fa5cc4a5dfc8f
child 380907 f9ef39b24287faa3cd9e3780b14ea9fe961fc394
push id21339
push userbmo:ttromey@mozilla.com
push dateThu, 23 Jun 2016 14:11:17 +0000
reviewersjryans
bugs1273941
milestone50.0a1
Bug 1273941 - replace uses of promise.defer in devtools/client/framework; r?jryans MozReview-Commit-ID: GwgbcXOmvtK
devtools/client/framework/attach-thread.js
devtools/client/framework/devtools-browser.js
devtools/client/framework/devtools.js
devtools/client/framework/target.js
devtools/client/framework/test/browser_devtools_api.js
devtools/client/framework/test/browser_devtools_api_destroy.js
devtools/client/framework/test/browser_source-location-02.js
devtools/client/framework/test/browser_toolbox_options.js
devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
devtools/client/framework/test/browser_toolbox_options_enable_serviceworkers_testing.js
devtools/client/framework/test/browser_toolbox_sidebar.js
devtools/client/framework/test/browser_toolbox_sidebar_events.js
devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
devtools/client/framework/test/browser_toolbox_window_title_changes.js
devtools/client/framework/test/head.js
devtools/client/framework/test/helper_disable_cache.js
devtools/client/framework/test/shared-head.js
devtools/client/framework/test/shared-redux-head.js
devtools/client/framework/toolbox-hosts.js
devtools/client/framework/toolbox-options.js
devtools/client/framework/toolbox.js
devtools/client/memory/test/unit/head.js
--- a/devtools/client/framework/attach-thread.js
+++ b/devtools/client/framework/attach-thread.js
@@ -1,17 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=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/. */
 
 const {Cc, Ci, Cu} = require("chrome");
 const Services = require("Services");
-const promise = require("promise");
+const defer = require("devtools/shared/defer");
 
 function l10n(name) {
   const bundle = Services.strings.createBundle("chrome://devtools/locale/toolbox.properties");
   try {
     return bundle.GetStringFromName(name);
   } catch (e) {
     throw new Error("Failed loading l10n string: " + name);
   }
@@ -37,17 +37,17 @@ function handleThreadState(toolbox, even
       toolbox.selectTool("jsdebugger");
     }
   } else if (event === "resumed") {
     toolbox.unhighlightTool("jsdebugger");
   }
 }
 
 function attachThread(toolbox) {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   let target = toolbox.target;
   let { form: { chromeDebugger, actor } } = target;
   let threadOptions = {
     useSourceMaps: Services.prefs.getBoolPref("devtools.debugger.source-maps-enabled"),
     autoBlackBox: Services.prefs.getBoolPref("devtools.debugger.auto-black-box")
   };
 
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -10,16 +10,17 @@
  *
  * This module is loaded lazily by devtools-clhandler.js, once the first
  * browser window is ready (i.e. fired browser-delayed-startup-finished event)
  **/
 
 const {Cc, Ci, Cu} = require("chrome");
 const Services = require("Services");
 const promise = require("promise");
+const defer = require("devtools/shared/defer");
 const Telemetry = require("devtools/client/shared/telemetry");
 const { gDevTools } = require("./devtools");
 const { when: unload } = require("sdk/system/unload");
 
 // Load target and toolbox lazily as they need gDevTools to be fully initialized
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
@@ -232,17 +233,17 @@ var gDevToolsBrowser = exports.gDevTools
       DebuggerServer.init();
       DebuggerServer.addBrowserActors();
     }
     DebuggerServer.allowChromeProcess = true;
 
     let transport = DebuggerServer.connectPipe();
     let client = new DebuggerClient(transport);
 
-    let deferred = promise.defer();
+    let deferred = defer();
     client.connect().then(() => {
       client.mainRoot.listProcesses(response => {
         // Do nothing if there is only one process, the parent process.
         let contentProcesses = response.processes.filter(p => (!p.parent));
         if (contentProcesses.length < 1) {
           let msg = bundle.GetStringFromName("toolbox.noContentProcess.message");
           Services.prompt.alert(null, "", msg);
           deferred.reject("No content processes available.");
@@ -369,17 +370,17 @@ var gDevToolsBrowser = exports.gDevTools
   isWebIDEWidgetInstalled: function () {
     let widgetWrapper = CustomizableUI.getWidget("webide-button");
     return !!(widgetWrapper && widgetWrapper.provider == CustomizableUI.PROVIDER_API);
   },
 
   /**
    * The deferred promise will be resolved by WebIDE's UI.init()
    */
-  isWebIDEInitialized: promise.defer(),
+  isWebIDEInitialized: defer(),
 
   /**
    * Uninstall WebIDE widget
    */
   uninstallWebIDEWidget: function () {
     if (this.isWebIDEWidgetInstalled()) {
       CustomizableUI.removeWidgetFromArea("webide-button");
     }
--- a/devtools/client/framework/devtools.js
+++ b/devtools/client/framework/devtools.js
@@ -1,16 +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";
 
 const Services = require("Services");
 const promise = require("promise");
+const defer = require("devtools/shared/defer");
 
 // Load gDevToolsBrowser toolbox lazily as they need gDevTools to be fully initialized
 loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
 loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
 
 const {defaultTools: DefaultTools, defaultThemes: DefaultThemes} =
   require("devtools/client/definitions");
 const EventEmitter = require("devtools/shared/event-emitter");
@@ -388,17 +389,17 @@ DevTools.prototype = {
    *        The type of host (bottom, window, side)
    * @param {object} hostOptions
    *        Options for host specifically
    *
    * @return {Toolbox} toolbox
    *        The toolbox that was opened
    */
   showToolbox: function (target, toolId, hostType, hostOptions) {
-    let deferred = promise.defer();
+    let deferred = defer();
 
     let toolbox = this._toolboxes.get(target);
     if (toolbox) {
 
       let hostPromise = (hostType != null && toolbox.hostType != hostType) ?
           toolbox.switchHost(hostType) :
           promise.resolve(null);
 
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -1,16 +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";
 
 const { Ci } = require("chrome");
 const promise = require("promise");
+const defer = require("devtools/shared/defer");
 const EventEmitter = require("devtools/shared/event-emitter");
 const Services = require("Services");
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
 
@@ -182,17 +183,17 @@ TabTarget.prototype = {
    * }
    */
   getActorDescription: function (actorName) {
     if (!this.client) {
       throw new Error("TabTarget#getActorDescription() can only be called on " +
                       "remote tabs.");
     }
 
-    let deferred = promise.defer();
+    let deferred = defer();
 
     if (this._protocolDescription &&
         this._protocolDescription.types[actorName]) {
       deferred.resolve(this._protocolDescription.types[actorName]);
     } else {
       this.client.mainRoot.protocolDescription(description => {
         this._protocolDescription = description;
         deferred.resolve(description.types[actorName]);
@@ -364,17 +365,17 @@ TabTarget.prototype = {
    * for tools that support the Remote Debugging Protocol even for local
    * connections.
    */
   makeRemote: function () {
     if (this._remote) {
       return this._remote.promise;
     }
 
-    this._remote = promise.defer();
+    this._remote = defer();
 
     if (this.isLocalTab) {
       // Since a remote protocol connection will be made, let's start the
       // DebuggerServer here, once and for all tools.
       if (!DebuggerServer.initialized) {
         DebuggerServer.init();
         DebuggerServer.addBrowserActors();
       }
@@ -548,17 +549,17 @@ TabTarget.prototype = {
    */
   destroy: function () {
     // If several things call destroy then we give them all the same
     // destruction promise so we're sure to destroy only once
     if (this._destroyer) {
       return this._destroyer.promise;
     }
 
-    this._destroyer = promise.defer();
+    this._destroyer = defer();
 
     // Before taking any action, notify listeners that destruction is imminent.
     this.emit("close");
 
     if (this._tab) {
       this._teardownListeners();
     }
 
@@ -617,17 +618,17 @@ TabTarget.prototype = {
     let id = this._tab ? this._tab : (this._form && this._form.actor);
     return `TabTarget:${id}`;
   },
 
   /**
    * @see TabActor.prototype.onResolveLocation
    */
   resolveLocation(loc) {
-    let deferred = promise.defer();
+    let deferred = defer();
 
     this.client.request(Object.assign({
       to: this._form.actor,
       type: "resolveLocation",
     }, loc), deferred.resolve);
 
     return deferred.promise;
   },
--- a/devtools/client/framework/test/browser_devtools_api.js
+++ b/devtools/client/framework/test/browser_devtools_api.js
@@ -232,17 +232,17 @@ function DevToolPanel(iframeWindow, tool
   let textNode = doc.createTextNode("Some Tool");
 
   label.appendChild(textNode);
   doc.body.appendChild(label);*/
 }
 
 DevToolPanel.prototype = {
   open: function () {
-    let deferred = promise.defer();
+    let deferred = defer();
 
     executeSoon(() => {
       this._isReady = true;
       this.emit("ready");
       deferred.resolve(this);
     });
 
     return deferred.promise;
@@ -258,11 +258,11 @@ DevToolPanel.prototype = {
 
   get isReady() {
     return this._isReady;
   },
 
   _isReady: false,
 
   destroy: function DTI_destroy() {
-    return promise.defer(null);
+    return defer(null);
   },
 };
--- a/devtools/client/framework/test/browser_devtools_api_destroy.js
+++ b/devtools/client/framework/test/browser_devtools_api_destroy.js
@@ -12,17 +12,17 @@ function test() {
 function runTests(aTab) {
   let toolDefinition = {
     id: "testTool",
     visibilityswitch: "devtools.testTool.enabled",
     isTargetSupported: () => true,
     url: "about:blank",
     label: "someLabel",
     build: function (iframeWindow, toolbox) {
-      let deferred = promise.defer();
+      let deferred = defer();
       executeSoon(() => {
         deferred.resolve({
           target: toolbox.target,
           toolbox: toolbox,
           isReady: true,
           destroy: function () {},
         });
       });
--- a/devtools/client/framework/test/browser_source-location-02.js
+++ b/devtools/client/framework/test/browser_source-location-02.js
@@ -85,17 +85,17 @@ function createScript(url) {
     script.setAttribute("src", "${url}");
     document.body.appendChild(script);
   `;
   return evalInDebuggee(mm, command);
 }
 
 function waitForSourceShown(debuggerPanel, url) {
   let { panelWin } = debuggerPanel;
-  let deferred = promise.defer();
+  let deferred = defer();
 
   info(`Waiting for source ${url} to be shown in the debugger...`);
   panelWin.on(panelWin.EVENTS.SOURCE_SHOWN, function onSourceShown(_, source) {
     let sourceUrl = source.url || source.introductionUrl;
 
     if (sourceUrl.includes(url)) {
       panelWin.off(panelWin.EVENTS.SOURCE_SHOWN, onSourceShown);
       info(`Source shown for ${url}`);
--- a/devtools/client/framework/test/browser_toolbox_options.js
+++ b/devtools/client/framework/test/browser_toolbox_options.js
@@ -111,17 +111,17 @@ function* testSelect(select) {
   is(select.options[select.selectedIndex].value, GetPref(pref),
     "select starts out selected");
 
   for (let option of options) {
     if (options.indexOf(option) === select.selectedIndex) {
       continue;
     }
 
-    let deferred = promise.defer();
+    let deferred = defer();
     gDevTools.once("pref-changed", (event, data) => {
       if (data.pref == pref) {
         ok(true, "Correct pref was changed");
         is(GetPref(pref), option.value, "Preference been switched for " + pref);
       } else {
         ok(false, "Pref " + pref + " was not changed correctly");
       }
       deferred.resolve();
@@ -131,17 +131,17 @@ function* testSelect(select) {
     let changeEvent = new Event("change");
     select.dispatchEvent(changeEvent);
 
     yield deferred.promise;
   }
 }
 
 function* testMouseClick(node, prefValue) {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   let pref = node.getAttribute("data-pref");
   gDevTools.once("pref-changed", (event, data) => {
     if (data.pref == pref) {
       ok(true, "Correct pref was changed");
       is(data.oldValue, prefValue, "Previous value is correct for " + pref);
       is(data.newValue, !prefValue, "New value is correct for " + pref);
     } else {
@@ -213,17 +213,17 @@ function* testToggleTools() {
   yield toggleTool(firstTool);
   yield toggleTool(middleTool);
   yield toggleTool(middleTool);
   yield toggleTool(lastTool);
   yield toggleTool(lastTool);
 }
 
 function* toggleTool(node) {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   let toolId = node.getAttribute("id");
   if (node.checked) {
     gDevTools.once("tool-unregistered",
       checkUnregistered.bind(null, toolId, deferred));
   } else {
     gDevTools.once("tool-registered",
       checkRegistered.bind(null, toolId, deferred));
--- a/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
@@ -21,17 +21,17 @@ function test() {
       .then(cleanup, errorHandler);
   }, true);
 
   content.location = "data:text/html;charset=utf8,test for dynamically " +
                      "registering and unregistering tools";
 }
 
 function testPrefsAreRespectedWhenReopeningToolbox() {
-  let deferred = promise.defer();
+  let deferred = defer();
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   info("Closing toolbox to test after reopening");
   gDevTools.closeToolbox(target).then(() => {
     let tabTarget = TargetFactory.forTab(gBrowser.selectedTab);
     gDevTools.showToolbox(tabTarget)
       .then(testSelectTool)
       .then(() => {
@@ -40,17 +40,17 @@ function testPrefsAreRespectedWhenReopen
         deferred.resolve();
       });
   });
 
   return deferred.promise;
 }
 
 function testSelectTool(devtoolsToolbox) {
-  let deferred = promise.defer();
+  let deferred = defer();
   info("Selecting the options panel");
 
   toolbox = devtoolsToolbox;
   doc = toolbox.doc;
   toolbox.once("options-selected", (event, tool) => {
     ok(true, "Options panel selected via selectTool method");
     panelWin = tool.panelWin;
     deferred.resolve();
--- a/devtools/client/framework/test/browser_toolbox_options_enable_serviceworkers_testing.js
+++ b/devtools/client/framework/test/browser_toolbox_options_enable_serviceworkers_testing.js
@@ -82,17 +82,17 @@ function toggleServiceWorkersTestingChec
   }
 
   cbx.click();
 
   return promise.resolve();
 }
 
 function reload() {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
     deferred.resolve();
   }, true);
 
   executeInContent("devtools:test:reload", {}, {}, false);
   return deferred.promise;
--- a/devtools/client/framework/test/browser_toolbox_sidebar.js
+++ b/devtools/client/framework/test/browser_toolbox_sidebar.js
@@ -25,17 +25,17 @@ function test() {
 
   let toolDefinition = {
     id: "fakeTool4242",
     visibilityswitch: "devtools.fakeTool4242.enabled",
     url: toolURL,
     label: "FAKE TOOL!!!",
     isTargetSupported: () => true,
     build: function (iframeWindow, toolbox) {
-      let deferred = promise.defer();
+      let deferred = defer();
       executeSoon(() => {
         deferred.resolve({
           target: toolbox.target,
           toolbox: toolbox,
           isReady: true,
           destroy: function () {},
           panelDoc: iframeWindow.document,
         });
--- a/devtools/client/framework/test/browser_toolbox_sidebar_events.js
+++ b/devtools/client/framework/test/browser_toolbox_sidebar_events.js
@@ -20,17 +20,17 @@ function test() {
 
   let toolDefinition = {
     id: "testTool1072208",
     visibilityswitch: "devtools.testTool1072208.enabled",
     url: toolURL,
     label: "Test tool",
     isTargetSupported: () => true,
     build: function (iframeWindow, toolbox) {
-      let deferred = promise.defer();
+      let deferred = defer();
       executeSoon(() => {
         deferred.resolve({
           target: toolbox.target,
           toolbox: toolbox,
           isReady: true,
           destroy: function () {},
           panelDoc: iframeWindow.document,
         });
--- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -60,31 +60,31 @@ function runTools(target) {
       ok(panel.isReady, toolId + " panel should be ready");
     }
 
     yield toolbox.destroy();
   });
 }
 
 function getClient() {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   if (!DebuggerServer.initialized) {
     DebuggerServer.init();
     DebuggerServer.addBrowserActors();
   }
 
   let transport = DebuggerServer.connectPipe();
   let client = new DebuggerClient(transport);
 
   return client.connect().then(() => client);
 }
 
 function getTarget(client) {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   client.listTabs(tabList => {
     let target = TargetFactory.forRemoteTab({
       client: client,
       form: tabList.tabs[tabList.selected],
       chrome: false
     });
     deferred.resolve(target);
--- a/devtools/client/framework/test/browser_toolbox_window_title_changes.js
+++ b/devtools/client/framework/test/browser_toolbox_window_title_changes.js
@@ -32,26 +32,26 @@ function test() {
       .then(checkTitle.bind(null, NAME_1, URL_1, "toolbox undocked"))
 
     // switch to different tool and check title
       .then(() => toolbox.selectTool(TOOL_ID_2))
       .then(checkTitle.bind(null, NAME_1, URL_1, "tool changed"))
 
     // navigate to different local url and check title
       .then(function () {
-        let deferred = promise.defer();
+        let deferred = defer();
         target.once("navigate", () => deferred.resolve());
         gBrowser.loadURI(URL_2);
         return deferred.promise;
       })
       .then(checkTitle.bind(null, NAME_2, URL_2, "url changed"))
 
     // navigate to a real url and check title
       .then(() => {
-        let deferred = promise.defer();
+        let deferred = defer();
         target.once("navigate", () => deferred.resolve());
         gBrowser.loadURI(URL_3);
         return deferred.promise;
       })
       .then(checkTitle.bind(null, NAME_3, URL_3, "url changed"))
 
     // destroy toolbox, create new one hosted in a window (with a
     // different tool id), and check title
--- a/devtools/client/framework/test/head.js
+++ b/devtools/client/framework/test/head.js
@@ -51,17 +51,17 @@ function getSourceActor(aSources, aURL) 
 
 /**
  * Open a Scratchpad window.
  *
  * @return nsIDOMWindow
  *         The new window object that holds Scratchpad.
  */
 function* openScratchpadWindow() {
-  let { promise: p, resolve } = promise.defer();
+  let { promise: p, resolve } = defer();
   let win = ScratchpadManager.openScratchpad();
 
   yield once(win, "load");
 
   win.Scratchpad.addObserver({
     onReady: function () {
       win.Scratchpad.removeObserver(this);
       resolve(win);
@@ -77,17 +77,17 @@ function* openScratchpadWindow() {
  * @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 = promise.defer();
+  let def = defer();
   mm.addMessageListener(name, function onMessage(msg) {
     mm.removeMessageListener(name, onMessage);
     def.resolve(msg.data);
   });
   return def.promise;
 }
 
 /**
--- a/devtools/client/framework/test/helper_disable_cache.js
+++ b/devtools/client/framework/test/helper_disable_cache.js
@@ -83,17 +83,17 @@ function* setDisableCacheCheckboxChecked
 
     // We need to wait for all checkboxes to be updated and the docshells to
     // apply the new cache settings.
     yield waitForTick();
   }
 }
 
 function reloadTab(tabX) {
-  let def = promise.defer();
+  let def = defer();
   let browser = gBrowser.selectedBrowser;
 
   // once() doesn't work here so we use a standard handler instead.
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     info("Reloaded tab " + tabX.title);
     def.resolve();
   }, true);
--- a/devtools/client/framework/test/shared-head.js
+++ b/devtools/client/framework/test/shared-head.js
@@ -198,17 +198,17 @@ function synthesizeKeyShortcut(key, targ
  *        Number of deliveries to wait for.
  * @param {Boolean} useCapture
  *        Optional, for addEventListener/removeEventListener
  * @return A promise that resolves when the event has been handled
  */
 function waitForNEvents(target, eventName, numTimes, useCapture = false) {
   info("Waiting for event: '" + eventName + "' on " + target + ".");
 
-  let deferred = promise.defer();
+  let deferred = defer();
   let count = 0;
 
   for (let [add, remove] of [
     ["addEventListener", "removeEventListener"],
     ["addListener", "removeListener"],
     ["on", "off"]
   ]) {
     if ((add in target) && (remove in target)) {
@@ -257,31 +257,31 @@ function loadHelperScript(filePath) {
   Services.scriptloader.loadSubScript(testDir + "/" + filePath, this);
 }
 
 /**
  * Wait for a tick.
  * @return {Promise}
  */
 function waitForTick() {
-  let deferred = promise.defer();
+  let deferred = defer();
   executeSoon(deferred.resolve);
   return deferred.promise;
 }
 
 /**
  * This shouldn't be used in the tests, but is useful when writing new tests or
  * debugging existing tests in order to introduce delays in the test steps
  *
  * @param {Number} ms
  *        The time to wait
  * @return A promise that resolves when the time is passed
  */
 function wait(ms) {
-  let def = promise.defer();
+  let def = defer();
   content.setTimeout(def.resolve, ms);
   return def.promise;
 }
 
 /**
  * Open the toolbox in a given tab.
  * @param {XULNode} tab The tab the toolbox should be opened in.
  * @param {String} toolId Optional. The ID of the tool to be selected.
@@ -408,17 +408,17 @@ function evalInDebuggee(mm, script) {
  *        Function to invoke on popupshown event.
  * @param function onHidden
  *        Function to invoke on popuphidden event.
  * @return object
  *         A Promise object that is resolved after the popuphidden event
  *         callback is invoked.
  */
 function waitForContextMenu(popup, button, onShown, onHidden) {
-  let deferred = promise.defer();
+  let deferred = defer();
 
   function onPopupShown() {
     info("onPopupShown");
     popup.removeEventListener("popupshown", onPopupShown);
 
     onShown && onShown();
 
     // Use executeSoon() to get out of the popupshown event.
--- a/devtools/client/framework/test/shared-redux-head.js
+++ b/devtools/client/framework/test/shared-redux-head.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /* eslint no-unused-vars: [2, {"vars": "local"}] */
 /* import-globals-from ./shared-head.js */
-// Currently this file expects "promise" to be imported into scope.
+// Currently this file expects "defer" to be imported into scope.
 
 // Common utility functions for working with Redux stores.  The file is meant
 // to be safe to load in both mochitest and xpcshell environments.
 
 /**
  * A logging function that can be used from xpcshell and browser mochitest
  * environments.
  */
@@ -33,17 +33,17 @@ function commonLog(message) {
  *        The Redux store being used.
  * @param function predicate
  *        A function that returns true when the store has reached the expected
  *        state.
  * @return Promise
  *         Resolved once the store reaches the expected state.
  */
 function waitUntilState(store, predicate) {
-  let deferred = promise.defer();
+  let deferred = defer();
   let unsubscribe = store.subscribe(check);
 
   commonLog(`Waiting for state predicate "${predicate}"`);
   function check() {
     if (predicate(store.getState())) {
       commonLog(`Found state predicate "${predicate}"`);
       unsubscribe();
       deferred.resolve();
@@ -61,17 +61,17 @@ function waitUntilState(store, predicate
  * @param Store store
  *        The Redux store being used.
  * @param string actionType
  *        The expected action to wait for.
  * @return Promise
  *         Resolved once the expected action is emitted by the store.
  */
 function waitUntilAction(store, actionType) {
-  let deferred = promise.defer();
+  let deferred = defer();
   let unsubscribe = store.subscribe(check);
   let history = store.history;
   let index = history.length;
 
   commonLog(`Waiting for action "${actionType}"`);
   function check() {
     let action = history[index++];
     if (action && action.type === actionType) {
--- a/devtools/client/framework/toolbox-hosts.js
+++ b/devtools/client/framework/toolbox-hosts.js
@@ -3,16 +3,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";
 
 const EventEmitter = require("devtools/shared/event-emitter");
 const promise = require("promise");
+const defer = require("devtools/shared/defer");
 const Services = require("Services");
 const {DOMHelpers} = require("resource://devtools/client/shared/DOMHelpers.jsm");
 
 loader.lazyRequireGetter(this, "system", "devtools/shared/system");
 
 /* A host should always allow this much space for the page to be displayed.
  * There is also a min-height on the browser, but we still don't want to set
  * frame.height to be larger than that, since it can cause problems with
@@ -48,17 +49,17 @@ BottomHost.prototype = {
   type: "bottom",
 
   heightPref: "devtools.toolbox.footer.height",
 
   /**
    * Create a box at the bottom of the host tab.
    */
   create: function () {
-    let deferred = promise.defer();
+    let deferred = defer();
 
     let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     let ownerDocument = gBrowser.ownerDocument;
     this._nbox = gBrowser.getNotificationBox(this.hostTab.linkedBrowser);
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-horizontal-splitter");
 
@@ -189,17 +190,17 @@ SidebarHost.prototype = {
   type: "side",
 
   widthPref: "devtools.toolbox.sidebar.width",
 
   /**
    * Create a box in the sidebar of the host tab.
    */
   create: function () {
-    let deferred = promise.defer();
+    let deferred = defer();
 
     let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     let ownerDocument = gBrowser.ownerDocument;
     this._sidebar = gBrowser.getSidebarContainer(this.hostTab.linkedBrowser);
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-side-splitter");
 
@@ -272,17 +273,17 @@ WindowHost.prototype = {
   type: "window",
 
   WINDOW_URL: "chrome://devtools/content/framework/toolbox-window.xul",
 
   /**
    * Create a new xul window to contain the toolbox.
    */
   create: function () {
-    let deferred = promise.defer();
+    let deferred = defer();
 
     let flags = "chrome,centerscreen,resizable,dialog=no";
     let win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
                                      flags, null);
 
     let frameLoad = () => {
       win.removeEventListener("load", frameLoad, true);
       win.focus();
--- a/devtools/client/framework/toolbox-options.js
+++ b/devtools/client/framework/toolbox-options.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=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/. */
 
 "use strict";
 
 const Services = require("Services");
-const promise = require("promise");
+const defer = require("devtools/shared/defer");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const {Task} = require("devtools/shared/task");
 const {gDevTools} = require("devtools/client/framework/devtools");
 
 exports.OptionsPanel = OptionsPanel;
 
 XPCOMUtils.defineLazyGetter(this, "l10n", function () {
   let bundle = Services.strings.createBundle("chrome://devtools/locale/toolbox.properties");
@@ -391,17 +391,17 @@ OptionsPanel.prototype = {
     this.target.activeTab.reconfigure(options);
   },
 
   destroy: function () {
     if (this.destroyPromise) {
       return this.destroyPromise;
     }
 
-    let deferred = promise.defer();
+    let deferred = defer();
     this.destroyPromise = deferred.promise;
 
     this._removeListeners();
 
     if (this.target.activeTab) {
       this.disableJSNode.removeEventListener("click", this._disableJSClicked);
       // FF41+ automatically cleans up state in actor on disconnect
       if (!this.target.activeTab.traits.noTabReconfigureOnClose) {
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -9,16 +9,17 @@ const SPLITCONSOLE_ENABLED_PREF = "devto
 const SPLITCONSOLE_HEIGHT_PREF = "devtools.toolbox.splitconsoleHeight";
 const OS_HISTOGRAM = "DEVTOOLS_OS_ENUMERATED_PER_USER";
 const OS_IS_64_BITS = "DEVTOOLS_OS_IS_64_BITS_PER_USER";
 const SCREENSIZE_HISTOGRAM = "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER";
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 var {Cc, Ci, Cu} = require("chrome");
 var promise = require("promise");
+var defer = require("devtools/shared/defer");
 var Services = require("Services");
 var {Task} = require("devtools/shared/task");
 var {gDevTools} = require("devtools/client/framework/devtools");
 var EventEmitter = require("devtools/shared/event-emitter");
 var Telemetry = require("devtools/client/shared/telemetry");
 var HUDService = require("devtools/client/webconsole/hudservice");
 var viewSource = require("devtools/client/shared/view-source");
 var { attachThread, detachThread } = require("./attach-thread");
@@ -229,17 +230,17 @@ Toolbox.prototype = {
    * like to select the tool right away.
    *
    * @param  {String} id
    *         The id of the panel, for example "jsdebugger".
    * @returns Promise
    *          A promise that resolves once the panel is ready.
    */
   getPanelWhenReady: function (id) {
-    let deferred = promise.defer();
+    let deferred = defer();
     let panel = this.getPanel(id);
     if (panel) {
       deferred.resolve(panel);
     } else {
       this.on(id + "-ready", (e, panel) => {
         deferred.resolve(panel);
       });
     }
@@ -359,17 +360,17 @@ Toolbox.prototype = {
   },
 
   /**
    * Open the toolbox
    */
   open: function () {
     return Task.spawn(function* () {
       let iframe = yield this._host.create();
-      let domReady = promise.defer();
+      let domReady = defer();
 
       // Prevent reloading the document when the toolbox is opened in a tab
       let location = iframe.contentWindow.location.href;
       if (!location.startsWith(this._URL)) {
         iframe.setAttribute("src", this._URL);
       } else {
         // Update the URL so that onceDOMReady watch for the right url.
         this._URL = location;
@@ -1184,17 +1185,17 @@ Toolbox.prototype = {
    */
   loadTool: function (id) {
     if (id === "inspector" && !this._inspector) {
       return this.initInspector().then(() => {
         return this.loadTool(id);
       });
     }
 
-    let deferred = promise.defer();
+    let deferred = defer();
     let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
 
     if (iframe) {
       let panel = this._toolPanels.get(id);
       if (panel) {
         deferred.resolve(panel);
       } else {
         this.once(id + "-ready", panel => {
@@ -1252,17 +1253,17 @@ Toolbox.prototype = {
         gDevTools.emit(id + "-build", this, panel);
         this.emit(id + "-build", panel);
 
         // The panel can implement an 'open' method for asynchronous
         // initialization sequence.
         if (typeof panel.open == "function") {
           built = panel.open();
         } else {
-          let buildDeferred = promise.defer();
+          let buildDeferred = defer();
           buildDeferred.resolve(panel);
           built = buildDeferred.promise;
         }
       }
 
       // Wait till the panel is fully ready and fire 'ready' events.
       promise.resolve(built).then((panel) => {
         this._toolPanels.set(id, panel);
@@ -2183,17 +2184,17 @@ Toolbox.prototype = {
     if (!this.target.hasActor("profiler")) {
       return;
     }
 
     if (this._performanceFrontConnection) {
       return this._performanceFrontConnection.promise;
     }
 
-    this._performanceFrontConnection = promise.defer();
+    this._performanceFrontConnection = defer();
     this._performance = createPerformanceFront(this._target);
     yield this.performance.connect();
 
     // Emit an event when connected, but don't wait on startup for this.
     this.emit("profiler-connected");
 
     this.performance.on("*", this._onPerformanceFrontEvent);
     this._performanceFrontConnection.resolve(this.performance);
--- a/devtools/client/memory/test/unit/head.js
+++ b/devtools/client/memory/test/unit/head.js
@@ -12,16 +12,17 @@ var DevToolsUtils = require("devtools/sh
 DevToolsUtils.testing = true;
 DevToolsUtils.dumpn.wantLogging = true;
 DevToolsUtils.dumpv.wantVerbose = false;
 
 var { OS } = require("resource://gre/modules/osfile.jsm");
 var { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
 var { TargetFactory } = require("devtools/client/framework/target");
 var promise = require("promise");
+var defer = require("devtools/shared/defer");
 var { Task } = require("devtools/shared/task");
 var { expectState } = require("devtools/server/actors/common");
 var HeapSnapshotFileUtils = require("devtools/shared/heapsnapshot/HeapSnapshotFileUtils");
 var HeapAnalysesClient = require("devtools/shared/heapsnapshot/HeapAnalysesClient");
 var { addDebuggerToGlobal } = require("resource://gre/modules/jsdebugger.jsm");
 var Store = require("devtools/client/memory/store");
 var { L10N } = require("devtools/client/memory/utils");
 var SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);