diff --git a/browser/devtools/debugger/debugger-controller.js b/browser/devtools/debugger/debugger-controller.js index 026db7bbbc9f..9155fd4b9bd0 100644 --- a/browser/devtools/debugger/debugger-controller.js +++ b/browser/devtools/debugger/debugger-controller.js @@ -11,6 +11,7 @@ const Cu = Components.utils; const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties"; const NEW_SCRIPT_DISPLAY_DELAY = 200; // ms +const FETCH_SOURCE_RESPONSE_DELAY = 50; // ms const FRAME_STEP_CLEAR_DELAY = 100; // ms const CALL_STACK_PAGE_SIZE = 25; // frames @@ -1178,16 +1179,26 @@ SourceScripts.prototype = { * The source object coming from the active thread. * @param function aCallback * Function called after the source text has been loaded. + * @param function aOnTimeout + * Function called when the source text takes too long to fetch. */ - getText: function SS_getText(aSource, aCallback) { + getText: function SS_getText(aSource, aCallback, aOnTimeout) { // If already loaded, return the source text immediately. if (aSource.loaded) { aCallback(aSource.url, aSource.text); return; } + // If the source text takes too long to fetch, invoke a timeout to + // avoid blocking any operations. + if (aOnTimeout) { + var fetchTimeout = window.setTimeout(aOnTimeout, FETCH_SOURCE_RESPONSE_DELAY); + } + // Get the source text from the active thread. this.activeThread.source(aSource.source).source(function(aResponse) { + window.clearTimeout(fetchTimeout); + if (aResponse.error) { Cu.reportError("Error loading " + aSource.url + "\n" + aResponse.error); aCallback(aSource.url, ""); diff --git a/browser/devtools/debugger/debugger-panes.js b/browser/devtools/debugger/debugger-panes.js index d7248f190f79..efce1f0688e1 100644 --- a/browser/devtools/debugger/debugger-panes.js +++ b/browser/devtools/debugger/debugger-panes.js @@ -1260,6 +1260,7 @@ function GlobalSearchView() { MenuContainer.call(this); this._startSearch = this._startSearch.bind(this); this._onFetchSourceFinished = this._onFetchSourceFinished.bind(this); + this._onFetchSourceTimeout = this._onFetchSourceTimeout.bind(this); this._onFetchSourcesFinished = this._onFetchSourcesFinished.bind(this); this._createItemView = this._createItemView.bind(this); this._onScroll = this._onScroll.bind(this); @@ -1402,25 +1403,29 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, { this._sourcesCount = locations.length; this._searchedToken = aQuery; - this._fetchSources( - this._onFetchSourceFinished, - this._onFetchSourcesFinished, locations); + this._fetchSources(locations, { + onFetch: this._onFetchSourceFinished, + onTimeout: this._onFetchSourceTimeout, + onFinished: this._onFetchSourcesFinished + }); }, /** * Starts fetching all the sources, silently. * - * @param function aFetchCallback - * Called after each source is fetched. - * @param function aFetchedCallback - * Called if all the sources were already fetched. * @param array aLocations * The locations for the sources to fetch. + * @param object aCallbacks + * An object containing the callback functions to invoke: + * - onFetch: called after each source is fetched + * - onTimeout: called when a source's text takes too long to fetch + * - onFinished: called if all the sources were already fetched */ - _fetchSources: function DVGS__fetchSources(aFetchCallback, aFetchedCallback, aLocations) { + _fetchSources: + function DVGS__fetchSources(aLocations, { onFetch, onTimeout, onFinished }) { // If all the sources were already fetched, then don't do anything. if (this._cache.size == aLocations.length) { - aFetchedCallback(); + onFinished(); return; } @@ -1430,7 +1435,8 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, { continue; } let sourceItem = DebuggerView.Sources.getItemByValue(location); - DebuggerController.SourceScripts.getText(sourceItem.attachment, aFetchCallback); + let sourceObject = sourceItem.attachment; + DebuggerController.SourceScripts.getText(sourceObject, onFetch, onTimeout); } }, @@ -1452,10 +1458,24 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, { } }, + /** + * Called when a source's text takes too long to fetch. + */ + _onFetchSourceTimeout: function DVGS__onFetchSourceTimeout() { + // Remove the source from the load queue. + this._sourcesCount--; + + // Check if the remaining sources were fetched and stored in the cache. + if (this._cache.size == this._sourcesCount) { + this._onFetchSourcesFinished(); + } + }, + /** * Called when all the sources have been fetched. */ _onFetchSourcesFinished: function DVGS__onFetchSourcesFinished() { + // At least one source needs to be present to perform a global search. if (!this._sourcesCount) { return; }