зеркало из https://github.com/mozilla/gecko-dev.git
Bug 894595 - part 3 - Use asynchronous data collection for delayed save state calls; r=yoric
This commit is contained in:
Родитель
f54a6b1d55
Коммит
cabc97dd9e
|
@ -860,6 +860,8 @@ pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
|
|||
pref("browser.sessionstore.upgradeBackup.latestBuildID", "");
|
||||
// End-users should not run sessionstore in debug mode
|
||||
pref("browser.sessionstore.debug", false);
|
||||
// Enable asynchronous data collection by default.
|
||||
pref("browser.sessionstore.async", true);
|
||||
|
||||
// allow META refresh by default
|
||||
pref("accessibility.blockautorefresh", false);
|
||||
|
|
|
@ -151,7 +151,7 @@ let SessionSaverInternal = {
|
|||
delay = Math.max(this._lastSaveTime + gInterval - Date.now(), delay, 0);
|
||||
|
||||
// Schedule a state save.
|
||||
this._timeoutID = setTimeout(() => this._saveState(), delay);
|
||||
this._timeoutID = setTimeout(() => this._saveStateAsync(), delay);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -186,8 +186,7 @@ let SessionSaverInternal = {
|
|||
* update the corresponding caches.
|
||||
*/
|
||||
_saveState: function (forceUpdateAllWindows = false) {
|
||||
// Cancel any pending timeouts or just clear
|
||||
// the timeout if this is why we've been called.
|
||||
// Cancel any pending timeouts.
|
||||
this.cancel();
|
||||
|
||||
stopWatchStart("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
|
||||
|
@ -246,6 +245,33 @@ let SessionSaverInternal = {
|
|||
this._writeState(state);
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the current session state. Collects data asynchronously and calls
|
||||
* _saveState() to collect data again (with a cache hit rate of hopefully
|
||||
* 100%) and write to disk afterwards.
|
||||
*/
|
||||
_saveStateAsync: function () {
|
||||
// Allow scheduling delayed saves again.
|
||||
this._timeoutID = null;
|
||||
|
||||
// Check whether asynchronous data collection is disabled.
|
||||
if (!Services.prefs.getBoolPref("browser.sessionstore.async")) {
|
||||
this._saveState();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the last save time to make sure we wait at least another interval
|
||||
// length until we call _saveStateAsync() again.
|
||||
this.updateLastSaveTime();
|
||||
|
||||
// Save state synchronously after all tab caches have been filled. The data
|
||||
// for the tab caches is collected asynchronously. We will reuse this
|
||||
// cached data if the tab hasn't been invalidated in the meantime. In that
|
||||
// case we will just fall back to synchronous data collection for single
|
||||
// tabs.
|
||||
SessionStore.fillTabCachesAsynchronously().then(() => this._saveState());
|
||||
},
|
||||
|
||||
/**
|
||||
* Write the given state object to disk.
|
||||
*/
|
||||
|
|
|
@ -277,6 +277,10 @@ this.SessionStore = {
|
|||
return SessionStoreInternal.getCurrentState(aUpdateAll);
|
||||
},
|
||||
|
||||
fillTabCachesAsynchronously: function () {
|
||||
return SessionStoreInternal.fillTabCachesAsynchronously();
|
||||
},
|
||||
|
||||
/**
|
||||
* Backstage pass to implementation details, used for testing purpose.
|
||||
* Controlled by preference "browser.sessionstore.testmode".
|
||||
|
@ -1883,6 +1887,68 @@ let SessionStoreInternal = {
|
|||
return [true, canOverwriteTabs];
|
||||
},
|
||||
|
||||
/* ........ Async Data Collection .............. */
|
||||
|
||||
/**
|
||||
* Kicks off asynchronous data collection for all tabs that do not have any
|
||||
* cached data. The returned promise will only notify that the tab collection
|
||||
* has been finished without resolving to any data. The tab collection for a
|
||||
* a few or all tabs might have failed or timed out. By calling
|
||||
* fillTabCachesAsynchronously() and waiting for the promise to be resolved
|
||||
* before calling getCurrentState(), callers ensure that most of the data
|
||||
* should have been collected asynchronously, without blocking the main
|
||||
* thread.
|
||||
*
|
||||
* @return {Promise} the promise that is fulfilled when the tab data is ready
|
||||
*/
|
||||
fillTabCachesAsynchronously: function () {
|
||||
let countdown = 0;
|
||||
let deferred = Promise.defer();
|
||||
let activeWindow = this._getMostRecentBrowserWindow();
|
||||
|
||||
// The callback that will be called when a promise has been resolved
|
||||
// successfully, i.e. the tab data has been collected.
|
||||
function done() {
|
||||
if (--countdown === 0) {
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
// The callback that will be called when a promise is rejected, i.e. we
|
||||
// we couldn't collect the tab data because of a script error or a timeout.
|
||||
function fail(reason) {
|
||||
debug("Failed collecting tab data asynchronously: " + reason);
|
||||
done();
|
||||
}
|
||||
|
||||
this._forEachBrowserWindow(win => {
|
||||
if (!this._isWindowLoaded(win)) {
|
||||
// Bail out if the window hasn't even loaded, yet.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DirtyWindows.has(win) && win != activeWindow) {
|
||||
// Bail out if the window is not dirty and inactive.
|
||||
return;
|
||||
}
|
||||
|
||||
for (let tab of win.gBrowser.tabs) {
|
||||
if (!TabStateCache.has(tab)) {
|
||||
countdown++;
|
||||
TabState.collect(tab).then(done, fail);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// If no dirty tabs were found, return a resolved
|
||||
// promise because there is nothing to do here.
|
||||
if (countdown == 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/* ........ Saving Functionality .............. */
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче