--- a/devtools/client/framework/attach-thread.js
+++ b/devtools/client/framework/attach-thread.js
@@ -1,16 +1,15 @@
/* -*- 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 Services = require("Services");
-const defer = require("devtools/shared/defer");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
function handleThreadState(toolbox, event, packet) {
// Suppress interrupted events by default because the thread is
// paused/resumed a lot for various actions.
if (event === "paused" && packet.why.type === "interrupted") {
@@ -32,18 +31,16 @@ function handleThreadState(toolbox, even
toolbox.selectTool("jsdebugger", packet.why.type);
}
} else if (event === "resumed") {
toolbox.unhighlightTool("jsdebugger");
}
}
function attachThread(toolbox) {
- const deferred = defer();
-
const target = toolbox.target;
const { form: { chromeDebugger, actor } } = target;
// Sourcemaps are always turned off when using the new debugger
// frontend. This is because it does sourcemapping on the
// client-side, so the server should not do it.
let useSourceMaps = false;
let autoBlackBox = false;
@@ -53,68 +50,67 @@ function attachThread(toolbox) {
useSourceMaps = Services.prefs.getBoolPref("devtools.debugger.source-maps-enabled");
autoBlackBox = Services.prefs.getBoolPref("devtools.debugger.auto-black-box");
} else {
ignoreFrameEnvironment = true;
}
const threadOptions = { useSourceMaps, autoBlackBox, ignoreFrameEnvironment };
- const handleResponse = ([res, threadClient]) => {
- if (res.error) {
- deferred.reject(new Error("Couldn't attach to thread: " + res.error));
- return;
- }
- threadClient.addListener("paused", handleThreadState.bind(null, toolbox));
- threadClient.addListener("resumed", handleThreadState.bind(null, toolbox));
-
- if (!threadClient.paused) {
- deferred.reject(
- new Error("Thread in wrong state when starting up, should be paused")
- );
- }
+ return new Promise((resolve, reject) => {
+ const handleResponse = ([res, threadClient]) => {
+ if (res.error) {
+ reject(new Error("Couldn't attach to thread: " + res.error));
+ return;
+ }
- // These flags need to be set here because the client sends them
- // with the `resume` request. We make sure to do this before
- // resuming to avoid another interrupt. We can't pass it in with
- // `threadOptions` because the resume request will override them.
- threadClient.pauseOnExceptions(
- Services.prefs.getBoolPref("devtools.debugger.pause-on-exceptions"),
- Services.prefs.getBoolPref("devtools.debugger.ignore-caught-exceptions")
- );
+ threadClient.addListener("paused", handleThreadState.bind(null, toolbox));
+ threadClient.addListener("resumed", handleThreadState.bind(null, toolbox));
- threadClient.resume(res => {
- if (res.error === "wrongOrder") {
- const box = toolbox.getNotificationBox();
- box.appendNotification(
- L10N.getStr("toolbox.resumeOrderWarning"),
- "wrong-resume-order",
- "",
- box.PRIORITY_WARNING_HIGH
- );
+ if (!threadClient.paused) {
+ reject(new Error("Thread in wrong state when starting up, should be paused"));
}
- deferred.resolve(threadClient);
- });
- };
+ // These flags need to be set here because the client sends them
+ // with the `resume` request. We make sure to do this before
+ // resuming to avoid another interrupt. We can't pass it in with
+ // `threadOptions` because the resume request will override them.
+ threadClient.pauseOnExceptions(
+ Services.prefs.getBoolPref("devtools.debugger.pause-on-exceptions"),
+ Services.prefs.getBoolPref("devtools.debugger.ignore-caught-exceptions")
+ );
- if (target.isBrowsingContext) {
- // Attaching a tab, a browser process, or a WebExtensions add-on.
- target.activeTab.attachThread(threadOptions).then(handleResponse);
- } else if (target.isAddon) {
- // Attaching a legacy addon.
- target.client.attachAddon(actor).then(([res]) => {
- target.client.attachThread(res.threadActor).then(handleResponse);
- });
- } else {
- // Attaching an old browser debugger or a content process.
- target.client.attachThread(chromeDebugger).then(handleResponse);
- }
+ threadClient.resume(res => {
+ if (res.error === "wrongOrder") {
+ const box = toolbox.getNotificationBox();
+ box.appendNotification(
+ L10N.getStr("toolbox.resumeOrderWarning"),
+ "wrong-resume-order",
+ "",
+ box.PRIORITY_WARNING_HIGH
+ );
+ }
- return deferred.promise;
+ resolve(threadClient);
+ });
+ };
+
+ if (target.isBrowsingContext) {
+ // Attaching a tab, a browser process, or a WebExtensions add-on.
+ target.activeTab.attachThread(threadOptions).then(handleResponse);
+ } else if (target.isAddon) {
+ // Attaching a legacy addon.
+ target.client.attachAddon(actor).then(([res]) => {
+ target.client.attachThread(res.threadActor).then(handleResponse);
+ });
+ } else {
+ // Attaching an old browser debugger or a content process.
+ target.client.attachThread(chromeDebugger).then(handleResponse);
+ }
+ });
}
function detachThread(threadClient) {
threadClient.removeListener("paused");
threadClient.removeListener("resumed");
}
module.exports = { attachThread, detachThread };
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -304,40 +304,39 @@ var gDevToolsBrowser = exports.gDevTools
// Create a DebuggerServer in order to connect locally to it
DebuggerServer.init();
DebuggerServer.registerAllActors();
DebuggerServer.allowChromeProcess = true;
const transport = DebuggerServer.connectPipe();
const client = new DebuggerClient(transport);
- const deferred = defer();
- client.connect().then(() => {
- client.getProcess(processId)
- .then(response => {
- const options = {
- form: response.form,
- client: client,
- chrome: true,
- isBrowsingContext: false
- };
- return TargetFactory.forRemoteTab(options);
- })
- .then(target => {
- // Ensure closing the connection in order to cleanup
- // the debugger client and also the server created in the
- // content process
- target.on("close", () => {
- client.close();
+ return new Promise(resolve => {
+ client.connect().then(() => {
+ client.getProcess(processId)
+ .then(response => {
+ const options = {
+ form: response.form,
+ client: client,
+ chrome: true,
+ isBrowsingContext: false
+ };
+ return TargetFactory.forRemoteTab(options);
+ })
+ .then(target => {
+ // Ensure closing the connection in order to cleanup
+ // the debugger client and also the server created in the
+ // content process
+ target.on("close", () => {
+ client.close();
+ });
+ resolve(target);
});
- deferred.resolve(target);
- });
+ });
});
-
- return deferred.promise;
},
/**
* Open the Browser Content Toolbox for the provided gBrowser instance.
* Returns a promise that resolves with a toolbox instance. If no content process is
* available, the promise will be rejected and a message will be displayed to the user.
*
* Used by menus.js
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -1,16 +1,15 @@
/* 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 defer = require("devtools/shared/defer");
const EventEmitter = require("devtools/shared/event-emitter");
const Services = require("Services");
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
loader.lazyRequireGetter(this, "DebuggerClient",
"devtools/shared/client/debugger-client", true);
loader.lazyRequireGetter(this, "gDevTools",
"devtools/client/framework/devtools", true);
@@ -183,29 +182,27 @@ TabTarget.prototype = {
* }
*/
getActorDescription: function(actorName) {
if (!this.client) {
throw new Error("TabTarget#getActorDescription() can only be called on " +
"remote tabs.");
}
- const 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]);
- });
- }
-
- return deferred.promise;
+ return new Promise(resolve => {
+ if (this._protocolDescription &&
+ this._protocolDescription.types[actorName]) {
+ resolve(this._protocolDescription.types[actorName]);
+ } else {
+ this.client.mainRoot.protocolDescription(description => {
+ this._protocolDescription = description;
+ resolve(description.types[actorName]);
+ });
+ }
+ });
},
/**
* Returns a boolean indicating whether or not the specific actor
* type exists. Must be a remote target.
*
* @param {String} actorName
* @return {Boolean}
@@ -404,21 +401,19 @@ TabTarget.prototype = {
/**
* Adds remote protocol capabilities to the target, so that it can be used
* for tools that support the Remote Debugging Protocol even for local
* connections.
*/
makeRemote: async function() {
if (this._remote) {
- return this._remote.promise;
+ return this._remote;
}
- 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.
DebuggerServer.init();
// When connecting to a local tab, we only need the root actor.
// Then we are going to call DebuggerServer.connectToFrame and talk
// directly with actors living in the child process.
@@ -447,66 +442,68 @@ TabTarget.prototype = {
this._form = form;
this._url = form.url;
this._title = form.title;
}
this._setupRemoteListeners();
- const attachTab = async () => {
- try {
- const [ response, tabClient ] = await this._client.attachTab(this._form.actor);
- this.activeTab = tabClient;
- this.threadActor = response.threadActor;
- } catch (e) {
- this._remote.reject("Unable to attach to the tab: " + e);
- return;
- }
- attachConsole();
- };
+ this._remote = new Promise((resolve, reject) => {
+ const attachTab = async () => {
+ try {
+ const [response, tabClient] = await this._client.attachTab(this._form.actor);
+ this.activeTab = tabClient;
+ this.threadActor = response.threadActor;
+ } catch (e) {
+ reject("Unable to attach to the tab: " + e);
+ return;
+ }
+ attachConsole();
+ };
- const onConsoleAttached = ([response, consoleClient]) => {
- this.activeConsole = consoleClient;
+ const onConsoleAttached = ([response, consoleClient]) => {
+ this.activeConsole = consoleClient;
- this._onInspectObject = packet => this.emit("inspect-object", packet);
- this.activeConsole.on("inspectObject", this._onInspectObject);
+ this._onInspectObject = packet => this.emit("inspect-object", packet);
+ this.activeConsole.on("inspectObject", this._onInspectObject);
- this._remote.resolve(null);
- };
+ resolve(null);
+ };
- const attachConsole = () => {
- this._client.attachConsole(this._form.consoleActor, [])
- .then(onConsoleAttached, response => {
- this._remote.reject(
- `Unable to attach to the console [${response.error}]: ${response.message}`);
- });
- };
+ const attachConsole = () => {
+ this._client.attachConsole(this._form.consoleActor, [])
+ .then(onConsoleAttached, response => {
+ reject(
+ `Unable to attach to the console [${response.error}]: ${response.message}`);
+ });
+ };
- if (this.isLocalTab) {
- this._client.connect()
- .then(() => this._client.getTab({ tab: this.tab }))
- .then(response => {
- this._form = response.tab;
- this._url = this._form.url;
- this._title = this._form.title;
+ if (this.isLocalTab) {
+ this._client.connect()
+ .then(() => this._client.getTab({tab: this.tab}))
+ .then(response => {
+ this._form = response.tab;
+ this._url = this._form.url;
+ this._title = this._form.title;
- attachTab();
- }, e => this._remote.reject(e));
- } else if (this.isBrowsingContext) {
- // In the remote debugging case, the protocol connection will have been
- // already initialized in the connection screen code.
- attachTab();
- } else {
- // AddonActor and chrome debugging on RootActor doesn't inherit from
- // BrowsingContextTargetActor and doesn't need to be attached.
- attachConsole();
- }
+ attachTab();
+ }, e => reject(e));
+ } else if (this.isBrowsingContext) {
+ // In the remote debugging case, the protocol connection will have been
+ // already initialized in the connection screen code.
+ attachTab();
+ } else {
+ // AddonActor and chrome debugging on RootActor doesn't inherit from
+ // BrowsingContextTargetActor and doesn't need to be attached.
+ attachConsole();
+ }
+ });
- return this._remote.promise;
+ return this._remote;
},
/**
* Listen to the different events.
*/
_setupListeners: function() {
this.tab.addEventListener("TabClose", this);
this.tab.parentNode.addEventListener("TabSelect", this);
@@ -645,58 +642,58 @@ TabTarget.prototype = {
/**
* Target is not alive anymore.
*/
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 = defer();
-
- // Before taking any action, notify listeners that destruction is imminent.
- this.emit("close");
-
- if (this._tab) {
- this._teardownListeners();
+ return this._destroyer;
}
- const cleanupAndResolve = () => {
- this._cleanup();
- this._destroyer.resolve(null);
- };
- // If this target was not remoted, the promise will be resolved before the
- // function returns.
- if (this._tab && !this._client) {
- cleanupAndResolve();
- } else if (this._client) {
- // If, on the other hand, this target was remoted, the promise will be
- // resolved after the remote connection is closed.
- this._teardownRemoteListeners();
+ this._destroyer = new Promise(resolve => {
+ // Before taking any action, notify listeners that destruction is imminent.
+ this.emit("close");
+
+ if (this._tab) {
+ this._teardownListeners();
+ }
- if (this.isLocalTab) {
- // We started with a local tab and created the client ourselves, so we
- // should close it.
- this._client.close().then(cleanupAndResolve);
- } else if (this.activeTab) {
- // The client was handed to us, so we are not responsible for closing
- // it. We just need to detach from the tab, if already attached.
- // |detach| may fail if the connection is already dead, so proceed with
- // cleanup directly after this.
- this.activeTab.detach();
+ const cleanupAndResolve = () => {
+ this._cleanup();
+ resolve(null);
+ };
+ // If this target was not remoted, the promise will be resolved before the
+ // function returns.
+ if (this._tab && !this._client) {
cleanupAndResolve();
- } else {
- cleanupAndResolve();
+ } else if (this._client) {
+ // If, on the other hand, this target was remoted, the promise will be
+ // resolved after the remote connection is closed.
+ this._teardownRemoteListeners();
+
+ if (this.isLocalTab) {
+ // We started with a local tab and created the client ourselves, so we
+ // should close it.
+ this._client.close().then(cleanupAndResolve);
+ } else if (this.activeTab) {
+ // The client was handed to us, so we are not responsible for closing
+ // it. We just need to detach from the tab, if already attached.
+ // |detach| may fail if the connection is already dead, so proceed with
+ // cleanup directly after this.
+ this.activeTab.detach();
+ cleanupAndResolve();
+ } else {
+ cleanupAndResolve();
+ }
}
- }
+ });
- return this._destroyer.promise;
+ return this._destroyer;
},
/**
* Clean up references to what this target points to.
*/
_cleanup: function() {
if (this._tab) {
targets.delete(this._tab);
--- a/devtools/client/framework/test/browser_devtools_api_destroy.js
+++ b/devtools/client/framework/test/browser_devtools_api_destroy.js
@@ -12,26 +12,26 @@ function test() {
function runTests(aTab) {
const toolDefinition = {
id: "testTool",
visibilityswitch: "devtools.testTool.enabled",
isTargetSupported: () => true,
url: "about:blank",
label: "someLabel",
build: function(iframeWindow, toolbox) {
- const deferred = defer();
- executeSoon(() => {
- deferred.resolve({
- target: toolbox.target,
- toolbox: toolbox,
- isReady: true,
- destroy: function() {},
+ return new Promise(resolve => {
+ executeSoon(() => {
+ resolve({
+ target: toolbox.target,
+ toolbox: toolbox,
+ isReady: true,
+ destroy: function() {},
+ });
});
});
- return deferred.promise;
},
};
gDevTools.registerTool(toolDefinition);
const collectedEvents = [];
const target = TargetFactory.forTab(aTab);
--- a/devtools/client/framework/test/browser_toolbox_options.js
+++ b/devtools/client/framework/test/browser_toolbox_options.js
@@ -155,58 +155,59 @@ async function testSelect(select) {
for (const option of options) {
if (options.indexOf(option) === select.selectedIndex) {
continue;
}
const observer = new PrefObserver("devtools.");
- const deferred = defer();
let changeSeen = false;
- observer.once(pref, () => {
- changeSeen = true;
- is(GetPref(pref), option.value, "Preference been switched for " + pref);
- deferred.resolve();
+ const changeSeenPromise = new Promise(resolve => {
+ observer.once(pref, () => {
+ changeSeen = true;
+ is(GetPref(pref), option.value, "Preference been switched for " + pref);
+ resolve();
+ });
});
select.selectedIndex = options.indexOf(option);
const changeEvent = new Event("change");
select.dispatchEvent(changeEvent);
- await deferred.promise;
+ await changeSeenPromise;
ok(changeSeen, "Correct pref was changed");
observer.destroy();
}
}
async function testMouseClick(node, prefValue) {
- const deferred = defer();
-
const observer = new PrefObserver("devtools.");
const pref = node.getAttribute("data-pref");
let changeSeen = false;
- observer.once(pref, () => {
- changeSeen = true;
- is(GetPref(pref), !prefValue, "New value is correct for " + pref);
- deferred.resolve();
+ const changeSeenPromise = new Promise(resolve => {
+ observer.once(pref, () => {
+ changeSeen = true;
+ is(GetPref(pref), !prefValue, "New value is correct for " + pref);
+ resolve();
+ });
});
node.scrollIntoView();
// We use executeSoon here to ensure that the element is in view and
// clickable.
executeSoon(function() {
info("Click event synthesized for pref " + pref);
EventUtils.synthesizeMouseAtCenter(node, {}, panelWin);
});
- await deferred.promise;
+ await changeSeenPromise;
ok(changeSeen, "Correct pref was changed");
observer.destroy();
}
async function testToggleWebExtensions() {
const disabledExtensions = new Set();
const toggleableWebExtensions = toolbox.listWebExtensions();
@@ -397,54 +398,55 @@ async function testToggleTools() {
await toggleTool(getToolNode(lastToolId));
}
/**
* Toggle tool node checkbox. Note: because toggling the checkbox will result in
* re-rendering of the tool list, we must re-query the checkboxes every time.
*/
async function toggleTool(node) {
- const deferred = defer();
+ const toolId = node.getAttribute("id");
- const 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));
- }
+ const registeredPromise = new Promise(resolve => {
+ if (node.checked) {
+ gDevTools.once("tool-unregistered",
+ checkUnregistered.bind(null, toolId, resolve));
+ } else {
+ gDevTools.once("tool-registered",
+ checkRegistered.bind(null, toolId, resolve));
+ }
+ });
node.scrollIntoView();
EventUtils.synthesizeMouseAtCenter(node, {}, panelWin);
- await deferred.promise;
+ await registeredPromise;
}
-function checkUnregistered(toolId, deferred, data) {
+function checkUnregistered(toolId, resolve, data) {
if (data == toolId) {
ok(true, "Correct tool removed");
// checking tab on the toolbox
ok(!doc.getElementById("toolbox-tab-" + toolId),
"Tab removed for " + toolId);
} else {
ok(false, "Something went wrong, " + toolId + " was not unregistered");
}
- deferred.resolve();
+ resolve();
}
-async function checkRegistered(toolId, deferred, data) {
+async function checkRegistered(toolId, resolve, data) {
if (data == toolId) {
ok(true, "Correct tool added back");
// checking tab on the toolbox
const button = await lookupButtonForToolId(toolId);
ok(button, "Tab added back for " + toolId);
} else {
ok(false, "Something went wrong, " + toolId + " was not registered");
}
- deferred.resolve();
+ resolve();
}
function GetPref(name) {
const type = Services.prefs.getPrefType(name);
switch (type) {
case Services.prefs.PREF_STRING:
return Services.prefs.getCharPref(name);
case Services.prefs.PREF_INT:
--- a/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
@@ -21,48 +21,47 @@ function test() {
.then(testSelectTool)
.then(testToggleToolboxButtons)
.then(testPrefsAreRespectedWhenReopeningToolbox)
.then(cleanup, errorHandler);
});
}
function testPrefsAreRespectedWhenReopeningToolbox() {
- const deferred = defer();
const target = TargetFactory.forTab(gBrowser.selectedTab);
- info("Closing toolbox to test after reopening");
- gDevTools.closeToolbox(target).then(() => {
- const tabTarget = TargetFactory.forTab(gBrowser.selectedTab);
- gDevTools.showToolbox(tabTarget)
- .then(testSelectTool)
- .then(() => {
- info("Toolbox has been reopened. Checking UI state.");
- testPreferenceAndUIStateIsConsistent();
- deferred.resolve();
- });
+ return new Promise(resolve => {
+ info("Closing toolbox to test after reopening");
+ gDevTools.closeToolbox(target).then(() => {
+ const tabTarget = TargetFactory.forTab(gBrowser.selectedTab);
+ gDevTools.showToolbox(tabTarget)
+ .then(testSelectTool)
+ .then(() => {
+ info("Toolbox has been reopened. Checking UI state.");
+ testPreferenceAndUIStateIsConsistent();
+ resolve();
+ });
+ });
});
-
- return deferred.promise;
}
function testSelectTool(devtoolsToolbox) {
- const deferred = defer();
- info("Selecting the options panel");
+ return new Promise(resolve => {
+ info("Selecting the options panel");
+
+ toolbox = devtoolsToolbox;
+ doc = toolbox.doc;
- toolbox = devtoolsToolbox;
- doc = toolbox.doc;
- toolbox.once("options-selected", tool => {
- ok(true, "Options panel selected via selectTool method");
- panelWin = tool.panelWin;
- deferred.resolve();
+ toolbox.selectTool("options");
+ toolbox.once("options-selected", tool => {
+ ok(true, "Options panel selected via selectTool method");
+ panelWin = tool.panelWin;
+ resolve();
+ });
});
- toolbox.selectTool("options");
-
- return deferred.promise;
}
function testPreferenceAndUIStateIsConsistent() {
const checkNodes = [...panelWin.document.querySelectorAll(
"#enabled-toolbox-buttons-box input[type=checkbox]")];
const toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
for (const tool of toolbox.toolbarButtons) {
--- a/devtools/client/framework/test/browser_toolbox_sidebar.js
+++ b/devtools/client/framework/test/browser_toolbox_sidebar.js
@@ -16,27 +16,27 @@ function test() {
const toolDefinition = {
id: "fakeTool4242",
visibilityswitch: "devtools.fakeTool4242.enabled",
url: CHROME_URL_ROOT + "browser_toolbox_sidebar_toolURL.xul",
label: "FAKE TOOL!!!",
isTargetSupported: () => true,
build: function(iframeWindow, toolbox) {
- const deferred = defer();
- executeSoon(() => {
- deferred.resolve({
- target: toolbox.target,
- toolbox: toolbox,
- isReady: true,
- destroy: function() {},
- panelDoc: iframeWindow.document,
+ return new Promise(resolve => {
+ executeSoon(() => {
+ resolve({
+ target: toolbox.target,
+ toolbox: toolbox,
+ isReady: true,
+ destroy: function() {},
+ panelDoc: iframeWindow.document,
+ });
});
});
- return deferred.promise;
},
};
gDevTools.registerTool(toolDefinition);
addTab("about:blank").then(function(aTab) {
const target = TargetFactory.forTab(aTab);
gDevTools.showToolbox(target, toolDefinition.id).then(function(toolbox) {
--- a/devtools/client/framework/test/browser_toolbox_sidebar_events.js
+++ b/devtools/client/framework/test/browser_toolbox_sidebar_events.js
@@ -12,27 +12,27 @@ function test() {
const toolDefinition = {
id: "testTool1072208",
visibilityswitch: "devtools.testTool1072208.enabled",
url: CHROME_URL_ROOT + "browser_toolbox_sidebar_events.xul",
label: "Test tool",
isTargetSupported: () => true,
build: function(iframeWindow, toolbox) {
- const deferred = defer();
- executeSoon(() => {
- deferred.resolve({
- target: toolbox.target,
- toolbox: toolbox,
- isReady: true,
- destroy: function() {},
- panelDoc: iframeWindow.document,
+ return new Promise(resolve => {
+ executeSoon(() => {
+ resolve({
+ target: toolbox.target,
+ toolbox: toolbox,
+ isReady: true,
+ destroy: function() {},
+ panelDoc: iframeWindow.document,
+ });
});
});
- return deferred.promise;
},
};
gDevTools.registerTool(toolDefinition);
addTab("about:blank").then(function(aTab) {
const target = TargetFactory.forTab(aTab);
gDevTools.showToolbox(target, toolDefinition.id).then(function(toolbox) {
--- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -66,28 +66,26 @@ function getClient() {
const transport = DebuggerServer.connectPipe();
const client = new DebuggerClient(transport);
return client.connect().then(() => client);
}
function getTarget(client) {
- const deferred = defer();
-
- client.listTabs().then(tabList => {
- const target = TargetFactory.forRemoteTab({
- client: client,
- form: tabList.tabs[tabList.selected],
- chrome: false
+ return new Promise(resolve => {
+ client.listTabs().then(tabList => {
+ const target = TargetFactory.forRemoteTab({
+ client: client,
+ form: tabList.tabs[tabList.selected],
+ chrome: false
+ });
+ resolve(target);
});
- deferred.resolve(target);
});
-
- return deferred.promise;
}
function test() {
(async function() {
toggleAllTools(true);
await addTab("about:blank");
const client = await getClient();
--- a/devtools/client/framework/test/head.js
+++ b/devtools/client/framework/test/head.js
@@ -51,48 +51,48 @@ function getSourceActor(aSources, aURL)
/**
* Open a Scratchpad window.
*
* @return nsIDOMWindow
* The new window object that holds Scratchpad.
*/
async function openScratchpadWindow() {
- const { promise: p, resolve } = defer();
const win = ScratchpadManager.openScratchpad();
await once(win, "load");
- win.Scratchpad.addObserver({
- onReady: function() {
- win.Scratchpad.removeObserver(this);
- resolve(win);
- }
+ return new Promise(resolve => {
+ win.Scratchpad.addObserver({
+ onReady: function() {
+ win.Scratchpad.removeObserver(this);
+ resolve(win);
+ }
+ });
});
- return p;
}
/**
* Wait for a content -> chrome message on the message manager (the window
* messagemanager is used).
* @param {String} name The message name
* @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");
const mm = gBrowser.selectedBrowser.messageManager;
- const 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
* in doc_frame_script.js
* @param {Object} data Optional data to send along
@@ -202,25 +202,23 @@ function DevToolPanel(iframeWindow, tool
EventEmitter.decorate(this);
this._toolbox = toolbox;
this._window = iframeWindow;
}
DevToolPanel.prototype = {
open: function() {
- const deferred = defer();
-
- executeSoon(() => {
- this._isReady = true;
- this.emit("ready");
- deferred.resolve(this);
+ return new Promise(resolve => {
+ executeSoon(() => {
+ this._isReady = true;
+ this.emit("ready");
+ resolve(this);
+ });
});
-
- return deferred.promise;
},
get document() {
return this._window.document;
},
get target() {
return this._toolbox.target;
@@ -232,17 +230,17 @@ DevToolPanel.prototype = {
get isReady() {
return this._isReady;
},
_isReady: false,
destroy: function() {
- return defer(null);
+ return Promise.resolve(null);
},
};
/**
* Create a simple devtools test panel that implements the minimum API needed to be
* registered and opened in the toolbox.
*/
function createTestPanel(iframeWindow, toolbox) {
--- a/devtools/client/framework/test/helper_disable_cache.js
+++ b/devtools/client/framework/test/helper_disable_cache.js
@@ -89,29 +89,27 @@ async function setDisableCacheCheckboxCh
// We need to wait for all checkboxes to be updated and the docshells to
// apply the new cache settings.
await waitForTick();
}
}
function reloadTab(tabX) {
- const def = defer();
const browser = gBrowser.selectedBrowser;
- BrowserTestUtils.browserLoaded(browser).then(function() {
+ const reloadTabPromise = BrowserTestUtils.browserLoaded(browser).then(function() {
info("Reloaded tab " + tabX.title);
- def.resolve();
});
info("Reloading tab " + tabX.title);
const mm = loadFrameScriptUtils();
mm.sendAsyncMessage("devtools:test:reload");
- return def.promise;
+ return reloadTabPromise;
}
async function destroyTab(tabX) {
const toolbox = gDevTools.getToolbox(tabX.target);
let onceDestroyed = promise.resolve();
if (toolbox) {
onceDestroyed = gDevTools.once("toolbox-destroyed");
--- a/devtools/client/framework/toolbox-hosts.js
+++ b/devtools/client/framework/toolbox-hosts.js
@@ -3,17 +3,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 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, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
/* 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
@@ -238,46 +237,43 @@ WindowHost.prototype = {
type: "window",
WINDOW_URL: "chrome://devtools/content/framework/toolbox-window.xul",
/**
* Create a new xul window to contain the toolbox.
*/
create: function() {
- const deferred = defer();
+ return new Promise(resolve => {
+ const flags = "chrome,centerscreen,resizable,dialog=no";
+ const win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
+ flags, null);
- const flags = "chrome,centerscreen,resizable,dialog=no";
- const win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
- flags, null);
-
- const frameLoad = () => {
- win.removeEventListener("load", frameLoad, true);
- win.focus();
+ const frameLoad = () => {
+ win.removeEventListener("load", frameLoad, true);
+ win.focus();
- let key;
- if (AppConstants.platform === "macosx") {
- key = win.document.getElementById("toolbox-key-toggle-osx");
- } else {
- key = win.document.getElementById("toolbox-key-toggle");
- }
- key.removeAttribute("disabled");
+ let key;
+ if (AppConstants.platform === "macosx") {
+ key = win.document.getElementById("toolbox-key-toggle-osx");
+ } else {
+ key = win.document.getElementById("toolbox-key-toggle");
+ }
+ key.removeAttribute("disabled");
- this.frame = win.document.getElementById("toolbox-iframe");
- this.emit("ready", this.frame);
-
- deferred.resolve(this.frame);
- };
+ this.frame = win.document.getElementById("toolbox-iframe");
+ this.emit("ready", this.frame);
+ resolve(this.frame);
+ };
- win.addEventListener("load", frameLoad, true);
- win.addEventListener("unload", this._boundUnload);
+ win.addEventListener("load", frameLoad, true);
+ win.addEventListener("unload", this._boundUnload);
- this._window = win;
-
- return deferred.promise;
+ this._window = win;
+ });
},
/**
* Catch the user closing the window.
*/
_boundUnload: function(event) {
if (event.target.location != this.WINDOW_URL) {
return;
--- a/devtools/client/framework/toolbox-options.js
+++ b/devtools/client/framework/toolbox-options.js
@@ -1,16 +1,15 @@
/* 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 defer = require("devtools/shared/defer");
const {gDevTools} = require("devtools/client/framework/devtools");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
exports.OptionsPanel = OptionsPanel;
@@ -509,34 +508,33 @@ OptionsPanel.prototype = {
this.target.activeTab.reconfigure(options);
},
destroy: function() {
if (this.destroyPromise) {
return this.destroyPromise;
}
- const 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) {
- const options = {
- "javascriptEnabled": this._origJavascriptEnabled,
- "performReload": false
- };
- this.target.activeTab.reconfigure(options, deferred.resolve);
+ this.destroyPromise = new Promise(resolve => {
+ 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) {
+ const options = {
+ "javascriptEnabled": this._origJavascriptEnabled,
+ "performReload": false
+ };
+ this.target.activeTab.reconfigure(options, resolve);
+ } else {
+ resolve();
+ }
} else {
- deferred.resolve();
+ resolve();
}
- } else {
- deferred.resolve();
- }
+ });
this.panelWin = this.panelDoc = this.disableJSNode = this.toolbox = null;
return this.destroyPromise;
}
};
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -12,17 +12,16 @@ const SPLITCONSOLE_HEIGHT_PREF = "devtoo
const DISABLE_AUTOHIDE_PREF = "ui.popup.disable_autohide";
const HOST_HISTOGRAM = "DEVTOOLS_TOOLBOX_HOST";
const CURRENT_THEME_SCALAR = "devtools.current_theme";
const HTML_NS = "http://www.w3.org/1999/xhtml";
const REGEX_PANEL = /webconsole|inspector|jsdebugger|styleeditor|netmonitor|storage/;
var {Ci, Cc} = require("chrome");
var promise = require("promise");
-var defer = require("devtools/shared/defer");
const { debounce } = require("devtools/shared/debounce");
var Services = require("Services");
var ChromeUtils = require("ChromeUtils");
var {gDevTools} = require("devtools/client/framework/devtools");
var EventEmitter = require("devtools/shared/event-emitter");
var Telemetry = require("devtools/client/shared/telemetry");
const { getUnicodeUrl } = require("devtools/client/shared/unicode-url");
var { attachThread, detachThread } = require("./attach-thread");
@@ -176,18 +175,19 @@ function Toolbox(target, selectedTool, h
if (!selectedTool) {
selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
}
this._defaultToolId = selectedTool;
this._hostType = hostType;
- this._isOpenDeferred = defer();
- this.isOpen = this._isOpenDeferred.promise;
+ this.isOpen = new Promise(function(resolve) {
+ this._resolveIsOpen = resolve;
+ }.bind(this));
EventEmitter.decorate(this);
this._target.on("will-navigate", this._onWillNavigate);
this._target.on("navigate", this._refreshHostTitle);
this._target.on("frame-update", this._updateFrames);
this._target.on("inspect-object", this._onInspectObject);
@@ -307,27 +307,26 @@ 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) {
- const deferred = defer();
const panel = this.getPanel(id);
- if (panel) {
- deferred.resolve(panel);
- } else {
- this.on(id + "-ready", initializedPanel => {
- deferred.resolve(initializedPanel);
- });
- }
-
- return deferred.promise;
+ return new Promise(resolve => {
+ if (panel) {
+ resolve(panel);
+ } else {
+ this.on(id + "-ready", initializedPanel => {
+ resolve(initializedPanel);
+ });
+ }
+ });
},
/**
* This is a shortcut for getPanel(currentToolId) because it is much more
* likely that we're going to want to get the panel that we've just made
* visible
*/
getCurrentPanel: function() {
@@ -440,21 +439,22 @@ Toolbox.prototype = {
useOnlyShared: true
}).require;
if (this.win.location.href.startsWith(this._URL)) {
// Update the URL so that onceDOMReady watch for the right url.
this._URL = this.win.location.href;
}
- const domReady = defer();
const domHelper = new DOMHelpers(this.win);
- domHelper.onceDOMReady(() => {
- domReady.resolve();
- }, this._URL);
+ const domReady = new Promise(resolve => {
+ domHelper.onceDOMReady(() => {
+ resolve();
+ }, this._URL);
+ });
// Optimization: fire up a few other things before waiting on
// the iframe being ready (makes startup faster)
// Load the toolbox-level actor fronts and utilities now
await this._target.makeRemote();
// Start tracking network activity on toolbox open for targets such as tabs.
@@ -462,17 +462,17 @@ Toolbox.prototype = {
if (this._target.activeConsole) {
await this._target.activeConsole.startListeners([
"NetworkActivity",
]);
}
// Attach the thread
this._threadClient = await attachThread(this);
- await domReady.promise;
+ await domReady;
this.isReady = true;
const framesPromise = this._listFrames();
Services.prefs.addObserver("devtools.cache.disabled", this._applyCacheSettings);
Services.prefs.addObserver("devtools.serviceWorkers.testing.enabled",
this._applyServiceWorkersTestingSettings);
@@ -570,17 +570,17 @@ Toolbox.prototype = {
// If in testing environment, wait for performance connection to finish,
// so we don't have to explicitly wait for this in tests; ideally, all tests
// will handle this on their own, but each have their own tear down function.
if (flags.testing) {
await performanceFrontConnection;
}
this.emit("ready");
- this._isOpenDeferred.resolve();
+ this._resolveIsOpen();
}.bind(this))().catch(console.error);
},
/**
* loading React modules when needed (to avoid performance penalties
* during Firefox start up time).
*/
get React() {
@@ -1623,140 +1623,139 @@ Toolbox.prototype = {
* @param {string} id
* The id of the tool to load.
*/
loadTool: function(id) {
if (id === "inspector" && !this._inspector) {
return this.initInspector().then(() => this.loadTool(id));
}
- const deferred = defer();
let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
-
if (iframe) {
const panel = this._toolPanels.get(id);
- if (panel) {
- deferred.resolve(panel);
- } else {
- this.once(id + "-ready", initializedPanel => {
- deferred.resolve(initializedPanel);
- });
- }
- return deferred.promise;
- }
-
- // Retrieve the tool definition (from the global or the per-toolbox tool maps)
- const definition = this.getToolDefinition(id);
-
- if (!definition) {
- deferred.reject(new Error("no such tool id " + id));
- return deferred.promise;
- }
-
- iframe = this.doc.createElement("iframe");
- iframe.className = "toolbox-panel-iframe";
- iframe.id = "toolbox-panel-iframe-" + id;
- iframe.setAttribute("flex", 1);
- iframe.setAttribute("forceOwnRefreshDriver", "");
- iframe.tooltip = "aHTMLTooltip";
- iframe.style.visibility = "hidden";
-
- gDevTools.emit(id + "-init", this, iframe);
- this.emit(id + "-init", iframe);
-
- // If no parent yet, append the frame into default location.
- if (!iframe.parentNode) {
- const vbox = this.doc.getElementById("toolbox-panel-" + id);
- vbox.appendChild(iframe);
- vbox.visibility = "visible";
+ return new Promise(resolve => {
+ if (panel) {
+ resolve(panel);
+ } else {
+ this.once(id + "-ready", initializedPanel => {
+ resolve(initializedPanel);
+ });
+ }
+ });
}
- const onLoad = () => {
- // Prevent flicker while loading by waiting to make visible until now.
- iframe.style.visibility = "visible";
-
- // Try to set the dir attribute as early as possible.
- this.setIframeDocumentDir(iframe);
-
- // The build method should return a panel instance, so events can
- // be fired with the panel as an argument. However, in order to keep
- // backward compatibility with existing extensions do a check
- // for a promise return value.
- let built = definition.build(iframe.contentWindow, this);
-
- if (!(typeof built.then == "function")) {
- const panel = built;
- iframe.panel = panel;
-
- // The panel instance is expected to fire (and listen to) various
- // framework events, so make sure it's properly decorated with
- // appropriate API (on, off, once, emit).
- // In this case we decorate panel instances directly returned by
- // the tool definition 'build' method.
- if (typeof panel.emit == "undefined") {
- EventEmitter.decorate(panel);
- }
-
- 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 {
- const buildDeferred = defer();
- buildDeferred.resolve(panel);
- built = buildDeferred.promise;
- }
+ return new Promise((resolve, reject) => {
+ // Retrieve the tool definition (from the global or the per-toolbox tool maps)
+ const definition = this.getToolDefinition(id);
+
+ if (!definition) {
+ reject(new Error("no such tool id " + id));
+ return;
+ }
+
+ iframe = this.doc.createElement("iframe");
+ iframe.className = "toolbox-panel-iframe";
+ iframe.id = "toolbox-panel-iframe-" + id;
+ iframe.setAttribute("flex", 1);
+ iframe.setAttribute("forceOwnRefreshDriver", "");
+ iframe.tooltip = "aHTMLTooltip";
+ iframe.style.visibility = "hidden";
+
+ gDevTools.emit(id + "-init", this, iframe);
+ this.emit(id + "-init", iframe);
+
+ // If no parent yet, append the frame into default location.
+ if (!iframe.parentNode) {
+ const vbox = this.doc.getElementById("toolbox-panel-" + id);
+ vbox.appendChild(iframe);
+ vbox.visibility = "visible";
}
- // Wait till the panel is fully ready and fire 'ready' events.
- promise.resolve(built).then((panel) => {
- this._toolPanels.set(id, panel);
-
- // Make sure to decorate panel object with event API also in case
- // where the tool definition 'build' method returns only a promise
- // and the actual panel instance is available as soon as the
- // promise is resolved.
- if (typeof panel.emit == "undefined") {
- EventEmitter.decorate(panel);
+ const onLoad = () => {
+ // Prevent flicker while loading by waiting to make visible until now.
+ iframe.style.visibility = "visible";
+
+ // Try to set the dir attribute as early as possible.
+ this.setIframeDocumentDir(iframe);
+
+ // The build method should return a panel instance, so events can
+ // be fired with the panel as an argument. However, in order to keep
+ // backward compatibility with existing extensions do a check
+ // for a promise return value.
+ let built = definition.build(iframe.contentWindow, this);
+
+ if (!(typeof built.then == "function")) {
+ const panel = built;
+ iframe.panel = panel;
+
+ // The panel instance is expected to fire (and listen to) various
+ // framework events, so make sure it's properly decorated with
+ // appropriate API (on, off, once, emit).
+ // In this case we decorate panel instances directly returned by
+ // the tool definition 'build' method.
+ if (typeof panel.emit == "undefined") {
+ EventEmitter.decorate(panel);
+ }
+
+ 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 {
+ built = new Promise(resolve => {
+ resolve(panel);
+ });
+ }
}
- gDevTools.emit(id + "-ready", this, panel);
- this.emit(id + "-ready", panel);
-
- deferred.resolve(panel);
- }, console.error);
- };
-
- iframe.setAttribute("src", definition.url);
- if (definition.panelLabel) {
- iframe.setAttribute("aria-label", definition.panelLabel);
- }
-
- // Depending on the host, iframe.contentWindow is not always
- // defined at this moment. If it is not defined, we use an
- // event listener on the iframe DOM node. If it's defined,
- // we use the chromeEventHandler. We can't use a listener
- // on the DOM node every time because this won't work
- // if the (xul chrome) iframe is loaded in a content docshell.
- if (iframe.contentWindow) {
- const domHelper = new DOMHelpers(iframe.contentWindow);
- domHelper.onceDOMReady(onLoad);
- } else {
- const callback = () => {
- iframe.removeEventListener("DOMContentLoaded", callback);
- onLoad();
+ // Wait till the panel is fully ready and fire 'ready' events.
+ promise.resolve(built).then((panel) => {
+ this._toolPanels.set(id, panel);
+
+ // Make sure to decorate panel object with event API also in case
+ // where the tool definition 'build' method returns only a promise
+ // and the actual panel instance is available as soon as the
+ // promise is resolved.
+ if (typeof panel.emit == "undefined") {
+ EventEmitter.decorate(panel);
+ }
+
+ gDevTools.emit(id + "-ready", this, panel);
+ this.emit(id + "-ready", panel);
+
+ resolve(panel);
+ }, console.error);
};
- iframe.addEventListener("DOMContentLoaded", callback);
- }
-
- return deferred.promise;
+ iframe.setAttribute("src", definition.url);
+ if (definition.panelLabel) {
+ iframe.setAttribute("aria-label", definition.panelLabel);
+ }
+
+ // Depending on the host, iframe.contentWindow is not always
+ // defined at this moment. If it is not defined, we use an
+ // event listener on the iframe DOM node. If it's defined,
+ // we use the chromeEventHandler. We can't use a listener
+ // on the DOM node every time because this won't work
+ // if the (xul chrome) iframe is loaded in a content docshell.
+ if (iframe.contentWindow) {
+ const domHelper = new DOMHelpers(iframe.contentWindow);
+ domHelper.onceDOMReady(onLoad);
+ } else {
+ const callback = () => {
+ iframe.removeEventListener("DOMContentLoaded", callback);
+ onLoad();
+ };
+
+ iframe.addEventListener("DOMContentLoaded", callback);
+ }
+ });
},
/**
* Set the dir attribute on the content document element of the provided iframe.
*
* @param {IFrameElement} iframe
*/
setIframeDocumentDir: function(iframe) {
@@ -2833,18 +2832,16 @@ Toolbox.prototype = {
* Remove all UI elements, detach from target and clear up
*/
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;
}
- const deferred = defer();
- this._destroyer = deferred.promise;
this.emit("destroy");
this._target.off("inspect-object", this._onInspectObject);
this._target.off("will-navigate", this._onWillNavigate);
this._target.off("navigate", this._refreshHostTitle);
this._target.off("frame-update", this._updateFrames);
this.off("select", this._onToolSelected);
@@ -2972,17 +2969,18 @@ Toolbox.prototype = {
"next_panel": "none",
"reason": "toolbox_close",
"session_id": this.sessionId
});
// Finish all outstanding tasks (which means finish destroying panels and
// then destroying the host, successfully or not) before destroying the
// target.
- deferred.resolve(settleAll(outstanding)
+ this._destroyer = new Promise(resolve => {
+ resolve(settleAll(outstanding)
.catch(console.error)
.then(() => {
const api = this._netMonitorAPI;
this._netMonitorAPI = null;
return api ? api.destroy() : null;
}, console.error)
.then(() => {
this._removeHostListeners();
@@ -3024,16 +3022,17 @@ Toolbox.prototype = {
// Force GC to prevent long GC pauses when running tests and to free up
// memory in general when the toolbox is closed.
if (flags.testing) {
win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.garbageCollect();
}
}).catch(console.error));
+ });
const leakCheckObserver = ({wrappedJSObject: barrier}) => {
// Make the leak detector wait until this toolbox is properly destroyed.
barrier.client.addBlocker("DevTools: Wait until toolbox is destroyed",
this._destroyer);
};
const topic = "shutdown-leaks-before-check";
@@ -3080,44 +3079,48 @@ Toolbox.prototype = {
async initPerformance() {
// If target does not have performance actor (addons), do not
// even register the shared performance connection.
if (!this.target.hasActor("performance")) {
return promise.resolve();
}
if (this._performanceFrontConnection) {
- return this._performanceFrontConnection.promise;
+ return this._performanceFrontConnection;
}
- this._performanceFrontConnection = defer();
+ let resolvePerformance;
+ this._performanceFrontConnection = new Promise(function(resolve) {
+ resolvePerformance = resolve;
+ });
+
this._performance = createPerformanceFront(this._target);
await 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);
- return this._performanceFrontConnection.promise;
+ resolvePerformance(this.performance);
+ return this._performanceFrontConnection;
},
/**
* Disconnects the underlying Performance actor. If the connection
* has not finished initializing, as opening a toolbox does not wait,
* the performance connection destroy method will wait for it on its own.
*/
async destroyPerformance() {
if (!this.performance) {
return;
}
// If still connecting to performance actor, allow the
// actor to resolve its connection before attempting to destroy.
if (this._performanceFrontConnection) {
- await this._performanceFrontConnection.promise;
+ await this._performanceFrontConnection;
}
this.performance.off("*", this._onPerformanceFrontEvent);
await this.performance.destroy();
this._performance = null;
},
/**
* Return the style sheets front, creating it if necessary. If the