Bug 845842 - Use promises that resolve on later ticks; r=rnewman

This is meant as a temporary workaround until a built-in promise library
offers similar functionality.
This commit is contained in:
Gregory Szorc 2013-03-18 20:47:34 -07:00
parent 72d26537bd
commit 68098c1f10
6 changed files with 34 additions and 18 deletions

View File

@ -6,6 +6,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
this.EXPORTED_SYMBOLS = ["CommonUtils"];
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm")
@ -108,6 +109,19 @@ this.CommonUtils = {
Services.tm.currentThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
},
/**
* Return a promise resolving on some later tick.
*
* This a wrapper around Promise.resolve() that prevents stack
* accumulation and prevents callers from accidentally relying on
* same-tick promise resolution.
*/
laterTickResolvingPromise: function (value, prototype) {
let deferred = Promise.defer(prototype);
this.nextTick(deferred.resolve.bind(deferred, value));
return deferred.promise;
},
/**
* Spin the event loop and return once the next tick is executed.
*

View File

@ -396,7 +396,7 @@ AbstractHealthReporter.prototype = Object.freeze({
}
if (this._initialized) {
return Promise.resolve(this);
return CommonUtils.laterTickResolvingPromise(this);
}
return this._initializedDeferred.promise;
@ -793,7 +793,7 @@ AbstractHealthReporter.prototype = Object.freeze({
let decoder = new TextDecoder();
let json = JSON.parse(decoder.decode(buffer));
return Promise.resolve(json);
return CommonUtils.laterTickResolvingPromise(json);
},
function onError(error) {
return Promise.reject(error);
@ -1104,7 +1104,7 @@ HealthReporter.prototype = Object.freeze({
_onBagheeraResult: function (request, isDelete, result) {
this._log.debug("Received Bagheera result.");
let promise = Promise.resolve(null);
let promise = CommonUtils.laterTickResolvingPromise(null);
if (!result.transportSuccess) {
request.onSubmissionFailureSoft("Network transport error.");

View File

@ -391,7 +391,7 @@ CurrentSessionMeasurement.prototype = Object.freeze({
fields.set("firstPaint", [now, sessions.firstPaint]);
fields.set("sessionRestored", [now, sessions.sessionRestored]);
return Promise.resolve({
return CommonUtils.laterTickResolvingPromise({
days: new Metrics.DailyValues(),
singular: fields,
});
@ -626,14 +626,14 @@ AddonsProvider.prototype = Object.freeze({
this._listener = listener;
AddonManager.addAddonListener(this._listener);
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
},
onShutdown: function () {
AddonManager.removeAddonListener(this._listener);
this._listener = null;
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
},
collectConstantData: function () {

View File

@ -586,7 +586,7 @@ Provider.prototype = Object.freeze({
* initialization activities have completed.
*/
onInit: function () {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
},
/**
@ -599,7 +599,7 @@ Provider.prototype = Object.freeze({
* shutdown activities have completed.
*/
onShutdown: function () {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
},
/**
@ -611,7 +611,7 @@ Provider.prototype = Object.freeze({
* @return Promise<>
*/
collectConstantData: function () {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
},
/**
@ -627,7 +627,7 @@ Provider.prototype = Object.freeze({
* @return Promise<>
*/
collectDailyData: function () {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
},
/**

View File

@ -153,7 +153,7 @@ this.ProviderManager.prototype = Object.freeze({
}
if (this._providers.has(provider.name)) {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
}
let deferred = Promise.defer();
@ -222,13 +222,13 @@ this.ProviderManager.prototype = Object.freeze({
*/
ensurePullOnlyProvidersRegistered: function () {
if (this._pullOnlyProvidersRegistered) {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
}
let onFinished = function () {
this._pullOnlyProvidersRegistered = true;
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
}.bind(this);
return Task.spawn(function registerPullProviders() {
@ -245,13 +245,13 @@ this.ProviderManager.prototype = Object.freeze({
ensurePullOnlyProvidersUnregistered: function () {
if (!this._pullOnlyProvidersRegistered) {
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
}
let onFinished = function () {
this._pullOnlyProvidersRegistered = false;
return Promise.resolve();
return CommonUtils.laterTickResolvingPromise();
}.bind(this);
return Task.spawn(function unregisterPullProviders() {
@ -373,7 +373,7 @@ this.ProviderManager.prototype = Object.freeze({
}
}
return Promise.resolve(result);
return CommonUtils.laterTickResolvingPromise(result);
});
promises.push([provider.name, promise]);

View File

@ -980,7 +980,8 @@ MetricsStorageSqliteBackend.prototype = Object.freeze({
*/
registerMeasurement: function (provider, name, version) {
if (this.hasMeasurement(provider, name, version)) {
return Promise.resolve(this.measurementID(provider, name, version));
return CommonUtils.laterTickResolvingPromise(
this.measurementID(provider, name, version));
}
// Registrations might not be safe to perform in parallel with provider
@ -1067,7 +1068,8 @@ MetricsStorageSqliteBackend.prototype = Object.freeze({
throw new Error("Field already defined with different type: " + existingType);
}
return Promise.resolve(this.fieldIDFromMeasurement(measurementID, field));
return CommonUtils.laterTickResolvingPromise(
this.fieldIDFromMeasurement(measurementID, field));
}
let self = this;