How to prevent state races in an extension popup | ShopTools AI
ShopTools Guide

How to prevent state races in an extension popup

A popup design approach covering request context, guarded updates, startup dependencies and deterministic out-of-order response tests.

ShopTools AI lets users choose a country and find promo codes for a store. A popup supporting that task must avoid displaying an answer from an earlier request under a context that has already changed.

ShopTools AI search with fields for a store or purchase and shopping country
The ShopTools AI search interface on 14 September 2026. It finds offers; this screenshot does not demonstrate a discount in a shopping cart.

The following techniques form a design approach to check in your own implementation. They are not a claim that every mechanism described here is already implemented this way in ShopTools.

Render one coherent state snapshot

Separate data fetching, state updates and rendering. Counts, offer cards and empty states should come from the same snapshot. Rendering should not initiate another round of requests.

Map startup dependencies before adding concurrency. Merchant context must exist before domain filtering, and saved manual preferences must be considered before settling on a country. Independent reads can run together.

Guard every state update

Give each operation a request sequence number and capture its relevant context: query, country, tab and merchant. Before committing the result, compare that snapshot with the current state. Discard a response that no longer belongs.

The query text alone is not enough if the same phrase is repeated for another country. A tab ID does not establish that the page is unchanged either: the tab may have navigated.

Keep distinct safeguards distinct

Single-flight fetching lets several consumers share the same in-progress request. It avoids duplicate downloads, but each consumer must still check whether the returned data belongs to its current context.

A render may remove the DOM nodes a callback captured earlier. Do not blindly mutate a saved button reference. Update state and the current view only while the relevant popup still exists.

Delegating events to a stable container can simplify list replacement. Design any operation that must outlive the popup separately from its DOM, with an explicit plan for restoring its state.

Control completion order in tests

  1. Start request A, then B. Resolve B first and A last; the displayed result should still belong to B.
  2. Change the country or merchant while a request is pending and check that the old response is discarded.
  3. Close the popup or replace its list before completion; detached nodes must not be updated.
  4. Start another scan and confirm that the final status belongs to the newer operation.

Manually resolved promises make these cases more reliable than arbitrary delays. Passing them establishes state consistency, not offer freshness. Validating the data and the coupon's conditions remains a separate responsibility.

By the ShopTools AI editorial team.

Some ShopTools links are affiliate links. ShopTools may earn a commission on a qualifying purchase confirmed by the retailer; a click alone does not guarantee a commission.

Prepared with AI assistance. Product descriptions were checked against ShopTools code and interface; this is not a report of tests at every store.