Вимога: запити різних робіт мають зберігати обидва успішні результати незалежно від порядку завершення.
Простежити збій
| Крок | Застарілий знімок | Поточна колекція |
|---|---|---|
| A і B починаються | Обидва URL порожні | Обидва URL порожні |
| B завершується | A порожній; B заданий | A порожній; B заданий |
| A завершується | A заданий; B стертий | A заданий; B збережений |
Обидва callbacks захопили колекцію з порожніми URL. B оновлюється першим. Коли A будує результат зі старої колекції, він повертає порожній URL для B.
Зміна для рев’ю
Callback має читати колекцію в момент застосування оновлення. Логіка map залишається тією самою.
До: map по захопленому знімку
const initial = artworks;
// Inside the completion callback:
artworks = initial.map((artwork, position) =>
position === index ? { ...artwork, url } : artwork
);Після: map по поточній колекції
artworks = artworks.map((artwork, position) =>
position === index ? { ...artwork, url } : artwork
);Це присвоєння змінній є невеликою моделлю. У React відповідна зміна використовує функціональне оновлення стану, як у розборі галереї.
Запустити перевірку
Завантажити media-update.test.ts, потім запустити через Bun:
bun test ./media-update.test.ts
Прочитати повний тест
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' },
]);
});Тест спочатку завершує B й перевіряє результат, поки A очікує. Потім завершує A та перевіряє обидва URL. Щоб відтворити баг, додайте const initial = artworks; перед const pending та замініть artworks = artworks.map на artworks = initial.map.
Що це встановлює
Робочий приклад проходить. Версія із застарілим знімком падає на останній перевірці, бо URL для B стає порожнім. Обидві версії запускалися на Bun 1.4.2.
Це перевірка колекції з незмінним складом і незалежними оновленнями різних елементів. Вона не перевіряє зміну порядку колекції, два запити одного елемента, рендеринг React, завершення дії URL або демонтування. Для них потрібні окремі випадки.