A product filter receives its response quickly, yet the shopper still waits for the grid to react. The network waterfall looks reassuring because it describes only part of the journey. Data must become usable objects, pass through application logic, and eventually produce a visible result. A fast transfer does not establish a fast interaction.
EcomToolkit recommends treating product-data processing as its own performance question. This guide focuses on JSON parsing and the work around it, with an original diagnostic workflow for ecommerce teams. The examples are illustrative; no payload size or processing time below is a universal storefront benchmark.
Table of Contents
- Separate the stages before changing the endpoint
- Build a small measurement that answers one question
- Read the evidence as a pipeline
- Send only the product data the interaction needs
- Decide whether reuse or a worker is justified
- Protect correctness during the performance change
- The EcomToolkit view
Separate the stages before changing the endpoint
Begin with one reproducible action: selecting a size, changing a collection filter, or opening a product configurator. Write down when the action starts, when the response arrives, when usable data exists, and when the interface reflects the result. Those boundaries prevent the investigation from assigning every delay to the server.
MDN documents JSON.parse as the operation that converts a JSON string into a JavaScript value. An explicit call executes synchronously. If you call it on the main thread, that call must finish before subsequent JavaScript in the same task can proceed. A reviver adds transformations during this process.
The Response.json documentation describes an asynchronous method that reads the response body and resolves with a parsed value. Do not assume its elapsed duration represents pure parser CPU time, or that every browser performs all its internal work identically. Measure the shopper-facing result and inspect a trace before naming the bottleneck.
Build a small measurement that answers one question
For an explicit parsing path, start with text that has already been obtained. The following diagnostic separates that parse call from a later transformation. It deliberately excludes network time and rendering, so it cannot be reported as total filter latency.
function inspectProductData(text) {
const started = performance.now();
const data = JSON.parse(text);
const parsed = performance.now();
const available = data.products.filter(p => p.available);
const finished = performance.now();
return {
products: available,
parseMs: parsed - started,
filterMs: finished - parsed
};
}
This example assumes a validated payload with a products array and boolean availability fields. Production code needs appropriate error handling and schema checks. Do not silently treat a parsing failure as an empty collection: an apparently successful zero-results page can hide a broken endpoint and send shoppers away.
Run the measurement across realistic catalogue sizes and representative devices. Record the browser version, build, product count and interaction scenario. Repeat measurements to see variability, but avoid tight synthetic loops that create an unrealistic warm execution pattern. A single fast desktop run is weak evidence about a slower customer’s phone.
Read the evidence as a pipeline
Suppose an illustrative trace shows 90 milliseconds obtaining the body, 35 milliseconds in an explicit parse, 80 milliseconds transforming products and 55 milliseconds updating the interface. These invented figures help assign work, but overlapping asynchronous stages must not be added indiscriminately. Use consistent start and end markers on the same journey.
| Observed delay | Evidence to collect | First investigation |
|---|---|---|
| Waiting for response headers | Request timing and server trace | Backend or connection path |
| Large body transfer | Transferred and decoded size | Fields, records and compression |
| Long explicit parse | Main-thread trace around the call | Payload shape and size |
| Slow product transformation | Function timing and call count | Repeated scans and derived data |
| Late visible update | Rendering trace and interaction state | DOM work and scheduling |
A useful diagnosis might be that each filter response reparses the same large catalogue and rebuilds a lookup table. Another might be that parsing is inexpensive but a nested availability scan is costly. Both appear to the shopper as a frozen grid; they require different fixes.
The long-task guidance from web.dev explains how lengthy main-thread tasks delay other work. Breaking a surrounding loop into smaller tasks does not interrupt one synchronous parse already underway. That boundary matters when choosing between scheduling changes and reducing the amount of data processed.

Send only the product data the interaction needs
A collection card rarely needs every product description, every media rendition, every translated field and the complete inventory history. Define the response around the current operation. Keep enough information for correct price, availability, variant selection and accessible labels; move unrelated detail behind a separate, justified request.
Compare the actual field usage with the response schema. A developer can mark which fields the grid reads during initial rendering and which are used only after a card is opened. Ask the merchandising team which visible features must remain. This produces a specific reduction plan rather than a blind instruction to make JSON smaller.
Compression helps transfer size, but decompressed text still needs processing. Our Brotli and transfer-budget guide addresses that network layer. A response can compress well because it repeats many field names while still constructing a substantial number of objects in memory.
Pagination can reduce each interaction’s workload, provided its semantics fit the experience. Preserve total-result meaning, sort stability, filter correctness and keyboard navigation. Test whether the extra requests introduced by smaller pages outweigh the processing saved. A compact payload that causes repeated loading interruptions may not improve the journey.
Decide whether reuse or a worker is justified
If the same immutable response is processed repeatedly during one page visit, consider reusing the parsed result or a derived lookup. Define who owns that state and when it becomes stale. Price, inventory and market context can change; a cache needs an invalidation rule, not merely a convenient global variable.
A worker may help when there is enough independent CPU work to justify communication and setup. It is not a free speed multiplier. Read our worker transfer and round-trip guide before moving a catalogue between threads. Sending a large object back can introduce another cost that the original parse measurement never included.
Keep the result needed by the main thread small where possible. For example, an independent filter calculation might return matching identifiers instead of a second copy of every product record. Evaluate the complete round trip, including the eventual DOM update, because the shopper waits for the final usable state.
Avoid adding a worker merely because a payload sounds large. Start with the trace. If the expensive stage is constructing thousands of card elements after a modest parse, moving only the parser will leave the main problem in place. Performance work should remove the measured constraint.
Protect correctness during the performance change
A smaller payload can accidentally remove a field used only in a rare market or product type. Build a compact comparison set containing a sold-out product, a multi-variant item, a discounted product and a product with missing optional media. Confirm that the visible result and purchasable variant remain correct.
| Proposed change | Correctness check | Performance check |
|---|---|---|
| Remove unused fields | All card states still render | Decoded size and processing time |
| Reuse parsed data | Price and market invalidation | Repeat interaction latency |
| Precompute lookup | Stable product identifiers | Transformation call count |
| Move work to a worker | Equivalent matching products | Complete round-trip duration |
| Paginate results | Sort and filter consistency | First and subsequent result latency |
Also test failure recovery. A timeout, malformed response or interrupted navigation should produce a recoverable state without leaving an enabled button attached to stale product data. Record the failure mode separately from successful interaction timing so an apparently faster median does not conceal more abandoned journeys.

The EcomToolkit view
The most useful product-data budget is attached to a shopping action and a device class. Transferred bytes, parsing time and rendering work are complementary measurements. None should become a substitute for confirming that the shopper can choose the correct item and continue without a stalled interface.
Bring one reproducible filter or configurator delay to an EcomToolkit performance review. The goal is a trace-supported change with a clear owner, a correctness check and a measurable interaction outcome, rather than a smaller network number with no visible benefit.
For the next analytical step, read our guide to price-formatting costs and safe formatter reuse in product grids.