diff --git a/devtools/client/debugger/new/src/actions/sources/loadSourceText.js b/devtools/client/debugger/new/src/actions/sources/loadSourceText.js index 9bfb9c79eb86..66c31bbba899 100644 --- a/devtools/client/debugger/new/src/actions/sources/loadSourceText.js +++ b/devtools/client/debugger/new/src/actions/sources/loadSourceText.js @@ -5,7 +5,7 @@ // @flow import { PROMISE } from "../utils/middleware/promise"; -import { getSource } from "../../selectors"; +import { getSource, getSourcesEpoch } from "../../selectors"; import { setBreakpointPositions } from "../breakpoints"; import * as parser from "../../workers/parser"; @@ -44,6 +44,7 @@ async function loadSource(state, source: Source, { sourceMaps, client }) { async function loadSourceTextPromise( source: Source, + epoch: number, { dispatch, getState, client, sourceMaps }: ThunkArgs ): Promise { if (isLoaded(source)) { @@ -53,6 +54,7 @@ async function loadSourceTextPromise( await dispatch({ type: "LOAD_SOURCE_TEXT", sourceId: source.id, + epoch, [PROMISE]: loadSource(getState(), source, { sourceMaps, client }) }); @@ -82,12 +84,14 @@ export function loadSourceText(inputSource: ?Source) { // below in a way that Flow is happy with. const source = inputSource; - const id = source.id; + const epoch = getSourcesEpoch(thunkArgs.getState()); + + const id = `${epoch}:${source.id}`; let promise = requests.get(id); if (!promise) { promise = (async () => { try { - return await loadSourceTextPromise(source, thunkArgs); + return await loadSourceTextPromise(source, epoch, thunkArgs); } catch (e) { // TODO: This swallows errors for now. Ideally we would get rid of // this once we have a better handle on our async state management. diff --git a/devtools/client/debugger/new/src/actions/types/SourceAction.js b/devtools/client/debugger/new/src/actions/types/SourceAction.js index ff20f3c7824d..9704b681353a 100644 --- a/devtools/client/debugger/new/src/actions/types/SourceAction.js +++ b/devtools/client/debugger/new/src/actions/types/SourceAction.js @@ -10,7 +10,8 @@ import type { PromiseAction } from "../utils/middleware/promise"; export type LoadSourceAction = PromiseAction< {| +type: "LOAD_SOURCE_TEXT", - +sourceId: string + +sourceId: string, + +epoch: number |}, Source >; diff --git a/devtools/client/debugger/new/src/reducers/sources.js b/devtools/client/debugger/new/src/reducers/sources.js index 57ca8869a198..b152526c8156 100644 --- a/devtools/client/debugger/new/src/reducers/sources.js +++ b/devtools/client/debugger/new/src/reducers/sources.js @@ -36,6 +36,8 @@ type DisplayedSources = { [ThreadId]: { [SourceId]: boolean } }; type GetDisplayedSourcesSelector = OuterState => { [ThreadId]: SourcesMap }; export type SourcesState = { + epoch: number, + // All known sources. sources: SourcesMap, @@ -63,6 +65,7 @@ const emptySources = { export function initialSourcesState(): SourcesState { return { ...emptySources, + epoch: 1, selectedLocation: undefined, pendingSelectedLocation: prefs.pendingSelectedLocation, projectDirectoryRoot: prefs.projectDirectoryRoot, @@ -164,7 +167,10 @@ function update( return updateProjectDirectoryRoot(state, action.url); case "NAVIGATE": - return initialSourcesState(); + return { + ...initialSourcesState(), + epoch: state.epoch + 1 + }; case "SET_FOCUSED_SOURCE_ITEM": return { ...state, focusedItem: action.item }; @@ -296,10 +302,19 @@ function updateProjectDirectoryRoot(state: SourcesState, root: string) { * Update a source's loaded state fields * i.e. loadedState, text, error */ -function updateLoadedState(state, action: LoadSourceAction): SourcesState { +function updateLoadedState( + state: SourcesState, + action: LoadSourceAction +): SourcesState { const { sourceId } = action; let source; + // If there was a nativation between the time the action was started and + // completed, we don't want to update the store. + if (action.epoch !== state.epoch) { + return state; + } + if (action.status === "start") { source = { id: sourceId, loadedState: "loading" }; } else if (action.status === "error") { @@ -522,6 +537,10 @@ export function getSources(state: OuterState) { return state.sources.sources; } +export function getSourcesEpoch(state: OuterState) { + return state.sources.epoch; +} + export function getUrls(state: OuterState) { return state.sources.urls; }