Use a request timeline to fix stale results without relying on delay.
A search bug can look random when it is caused by response order. The user types one query, then another. The second request returns first, but the first request returns later and replaces the correct results. The network has not violated a promise. The application incorrectly assumed that completion order matches request order.
Draw the sequence with query identity, request identity, and visible results. A debounce may reduce requests, but it cannot guarantee ordering once requests overlap. Aborting an older request can reduce unnecessary work, but cancellation may race with completion. The state update must still know whether its result belongs to the current query and user context.
The query key should represent all inputs that affect the result. Search text alone is insufficient if the same text can be used within different accounts or projects. A cache shared across these contexts can display the wrong customer's data. Treat identity correctness and authorization as related but distinct checks: the server must authorize the request, while the client must place each permitted response in the right visible context.
Avoid solving the bug by discarding every response after a fixed delay. Fast and slow networks vary. A sequence token or current-query comparison expresses the actual rule. Cleanup also matters when a component unmounts. A response should not update a state owner that no longer represents the request's target.
At t3, the current query is anna, so R1 must not replace the visible results. One implementation stores the active request sequence when starting R2 and accepts an update only if the response sequence still matches. A query cache can instead store both responses under complete keys and render only the current key. If the account changes to B, account identity belongs in that key too.
Make success and error follow the same identity rule
A stale success is only one form of this bug. An older request can fail after the new request succeeds, and a global error handler can replace valid results with an irrelevant error. The same placement rule must govern loading, success, and failure. Each belongs to a request context, not to whichever screen happens to exist when the promise settles.
Use a context record with all result-defining inputs:
A response can be stored under its complete cache key while the current view reads only its selected key. Alternatively, a local component can compare its active sequence and context before changing visible state. These are implementation choices for the same rule. Neither permits the server to return unauthorized data; client placement is not a replacement for server authorization.
Reproduce an old error deterministically
Step
Controlled event
Required visible state
1
Start R1 for ann
Loading ann
2
Start R2 for anna
Loading anna
3
Resolve R2 successfully
Anna results
4
Reject R1 with network error
Anna results remain
5
Retry current query intentionally
New anna request tracked
The failure handler should remove or resolve R1's own pending entry, not mark the entire current view failed. If the application displays background-error history, it can attribute the error to the old request without replacing current results. This distinction prevents a fix that handles stale successes but leaves stale failures untouched.
A controlled transport can return unresolved promises and expose resolve/reject handles to the test. Resolve them in the desired order and assert the rendered context after each step. This is a teaching test plan, not a claim that a particular library is installed. A fixed sleep makes the scenario depend on machine timing and is a weaker control.
Cancellation is an optimization with a boundary
Abort the obsolete request when the transport supports it. This can reduce server or client work, but whether it stops remote processing depends on the protocol and stage. An abort can occur after the server finished or after a response reached another buffer. Therefore, keep the acceptance check even when cancellation is present.
Do not equate cancellation with an application error for the new query. The cancelled request's cleanup should not clear the newer request's loading state. A global boolean often hides this mistake: R1 finishes and sets loading false while R2 still runs. A request-aware pending set or current-request state makes the correct transition clear.
Suppose R1 is still pending, R2 completes, and then R1's cleanup runs. The visible view must remain the R2 result. Cleanup can release R1's resources without resetting the current result or error. This is one reason to model lifecycle events against stable request identity.
Consider pagination and selection
A search can also preserve an old page cursor after the query changes. The cursor may encode position within results for ann, so applying it to anna can skip records or produce an invalid request. Reset or replace pagination according to the API's cursor contract whenever result-defining inputs change.
Selection is another independent fact. If a user selected a customer before a search changes, decide whether selection remains valid, clears, or requires confirmation. Do not silently retarget selection by array index when result order changes. A selected customer ID and its authorized detail lookup are more precise than selected row 3.
Misconceptions and a transfer exercise
One misconception is that debounce eliminates races. It reduces starts but cannot order requests already in flight. A second is that successful server authorization guarantees correct client display. Both account A and account B requests can be individually permitted while A's old response is placed under B's heading.
Exercise: R1 uses account A/query anna/page 2. The user switches to account B with the same query, and the application retains page 2's old cursor. R1 later rejects. Define three repairs. Use complete account/query identity, reset or validate the cursor under the new context, and prevent the old error from replacing B's state. Award one point for each plus one for a deterministic schedule covering the rejection.
In the interview, explain the general rule before a framework-specific hook. Then show a success inversion and an error inversion. A good repair covers both, handles loading cleanup, and states what the server must still enforce. The result is a causal explanation rather than a delay that seems to work on one machine.
Exercise and solution
The user changes account after R2 starts, but the text remains anna. What breaks if the check compares only text? A's response can appear while B is selected. The solution compares the full query context or uses a complete cache key and current authorization. Award one point for the leak scenario, one for the full identity, and one for a deterministic test that resolves responses in the wrong order.
Interview probe and wrap-up
How would you test this without waiting for a flaky network? A strong answer uses controlled promises or a fake transport and resolves R2 before R1. Follow up with a rejected old request after a new success. A weak answer adds a one-second debounce and declares the race fixed. Replace timing guesses with a rule about which result the current view is allowed to accept.
R2 succeeds, then older R1 fails. Correct current view?
ARetry R1 as the current query automatically.BClear all cached queries.CReplace R2 with R1's error because it arrived last.DKeep R2 visible and resolve R1 only in its own context.
AAbort rewrites the response's account identity.BCancellation can race with completion, so obsolete callbacks must still be rejected.CAbort makes every later request serial.DAbort always waits for every remote effect.
Query changes but an old pagination cursor remains. What should be checked?
AWhether both queries use the same endpoint only.BWhether a cursor from the old query can be reused merely because the account is unchanged.CWhether the cursor is valid for the new complete query context.DWhether clearing visible rows without changing the cursor is sufficient.
AResolve requests in start order only.BResolve the new request, reject the old one, and assert the new result remains.CIncrease debounce until overlap is rare.DAssert only that R1 rejected.
Can you trace stale success, stale error, cancellation cleanup, and pagination context through one request identity model? State the relevant identifiers, failure boundary, and evidence in your own words before selecting your confidence.