Example review artifact · Maryan Prydatko

A slower response erases a completed update

This walkthrough uses the standalone example in my article. It illustrates how I want a review organized. It is not an export of a private pull request.

Requirement: requests for different artworks must preserve both successful results, regardless of completion order.

Follow the failure

Two requests, one shared collection
StepStale snapshotCurrent collection
A and B startBoth URLs emptyBoth URLs empty
B finishesA empty; B setA empty; B set
A finishesA set; B erasedA set; B retained

Both callbacks captured a collection where the URLs were empty. B updates first. When A builds its result from that old collection, it brings back B’s empty URL.

The change to inspect

The callback must read the collection at the time it applies the update. The mapping logic stays the same.

Before: map over the captured snapshot
const initial = artworks;

// Inside the completion callback:
artworks = initial.map((artwork, position) =>
  position === index ? { ...artwork, url } : artwork
);
After: map over the current collection
artworks = artworks.map((artwork, position) =>
  position === index ? { ...artwork, url } : artwork
);

This variable assignment is a small model. In React, the corresponding change uses a functional state update, as shown in the gallery case study.

Run the check

Download media-update.test.ts, then run it with Bun:

bun test ./media-update.test.ts
Read the complete test
import { expect, test } from 'bun:test';

test('a slower request preserves the result that arrived first', async () => {
  let artworks = [
    { id: 'a', url: '' },
    { id: 'b', url: '' },
  ];
  const a = Promise.withResolvers<string>();
  const b = Promise.withResolvers<string>();

  const pending = [a, b].map((request, index) =>
    request.promise.then(url => {
      artworks = artworks.map((artwork, position) =>
        position === index ? { ...artwork, url } : artwork
      );
    })
  );

  b.resolve('/b.webp');
  await pending[1];
  expect(artworks).toEqual([
    { id: 'a', url: '' },
    { id: 'b', url: '/b.webp' },
  ]);

  a.resolve('/a.webp');
  await pending[0];
  expect(artworks).toEqual([
    { id: 'a', url: '/a.webp' },
    { id: 'b', url: '/b.webp' },
  ]);
});

The test resolves B first and checks its result while A is pending. It then resolves A and checks both URLs. To reproduce the bug, add const initial = artworks; before const pending and change artworks = artworks.map to artworks = initial.map.

What this establishes

The working example passes. The stale-snapshot version fails at the final assertion because B’s URL becomes empty. Both versions were run with Bun 1.4.2.

This checks a fixed collection with independent updates to different entries. It does not test reordering the collection, two requests for the same entry, React rendering, URL expiry, or unmounting. Those require their own cases.