Bug 1126350 - Settle all toolbox destruction before final cleanup. r=pbrosset

This commit is contained in:
J. Ryan Stinnett 2015-02-10 12:37:21 -06:00
Родитель e5bb515f47
Коммит 925318d2b4
2 изменённых файлов: 79 добавлений и 2 удалений

Просмотреть файл

@ -47,6 +47,7 @@ loader.lazyGetter(this, "toolboxStrings", () => {
loader.lazyGetter(this, "Selection", () => require("devtools/framework/selection").Selection);
loader.lazyGetter(this, "InspectorFront", () => require("devtools/server/actors/inspector").InspectorFront);
loader.lazyRequireGetter(this, "DevToolsUtils", "devtools/toolkit/DevToolsUtils");
// White-list buttons that can be toggled to prevent adding prefs for
// addons that have manually inserted toolbarbuttons into DOM.
@ -1659,8 +1660,11 @@ Toolbox.prototype = {
// Finish all outstanding tasks (which means finish destroying panels and
// then destroying the host, successfully or not) before destroying the
// target.
this._destroyer = promise.all(outstanding)
.then(() => this.destroyHost()).then(null, console.error).then(() => {
this._destroyer = DevToolsUtils.settleAll(outstanding)
.catch(console.error)
.then(() => this.destroyHost())
.catch(console.error)
.then(() => {
// Targets need to be notified that the toolbox is being torn down.
// This is done after other destruction tasks since it may tear down
// fronts and the debugger transport which earlier destroy methods may

Просмотреть файл

@ -568,3 +568,76 @@ function convertToUnicode(aString, aCharset=null) {
return aString;
}
}
/**
* Returns a promise that is resolved or rejected when all promises have settled
* (resolved or rejected).
*
* This differs from Promise.all, which will reject immediately after the first
* rejection, instead of waiting for the remaining promises to settle.
*
* @param values
* Iterable of promises that may be pending, resolved, or rejected. When
* when all promises have settled (resolved or rejected), the returned
* promise will be resolved or rejected as well.
*
* @return A new promise that is fulfilled when all values have settled
* (resolved or rejected). Its resolution value will be an array of all
* resolved values in the given order, or undefined if values is an
* empty array. The reject reason will be forwarded from the first
* promise in the list of given promises to be rejected.
*/
exports.settleAll = values => {
if (values === null || typeof(values[Symbol.iterator]) != "function") {
throw new Error("settleAll() expects an iterable.");
}
let deferred = promise.defer();
values = Array.isArray(values) ? values : [...values];
let countdown = values.length;
let resolutionValues = new Array(countdown);
let rejectionValue;
let rejectionOccurred = false;
if (!countdown) {
deferred.resolve(resolutionValues);
return deferred.promise;
}
function checkForCompletion() {
if (--countdown > 0) {
return;
}
if (!rejectionOccurred) {
deferred.resolve(resolutionValues);
} else {
deferred.reject(rejectionValue);
}
}
for (let i = 0; i < values.length; i++) {
let index = i;
let value = values[i];
let resolver = result => {
resolutionValues[index] = result;
checkForCompletion();
};
let rejecter = error => {
if (!rejectionOccurred) {
rejectionValue = error;
rejectionOccurred = true;
}
checkForCompletion();
};
if (value && typeof(value.then) == "function") {
value.then(resolver, rejecter);
} else {
// Given value is not a promise, forward it as a resolution value.
resolver(value);
}
}
return deferred.promise;
};