Najwyżej trzy aktywne operacje
Polecenie: napisz mapLimited(items, limit, fn). Wyniki mają zachować kolejność wejścia; jeden błąd nie usuwa pozostałych wyników. Sprawdź pustą listę i niepoprawny limit. W rozszerzeniu dodaj anulowanie.
Sprawdza: Promise, liczbę równoczesnych działań i błędy.
Kontrakt z testów referencyjnych: funkcja jest asynchroniczna i zwraca tablicę w formacie Promise.allSettled ({status: 'fulfilled', value} lub {status: 'rejected', reason}). Niepoprawny limit kończy się RangeError. Opcjonalny czwarty argument signal (AbortSignal) zatrzymuje rozpoczynanie kolejnych elementów — te dostają status rejected.
Dopytanie: czym limit jednoczesnych odczytów różni się od limitu na sekundę? Kod nie zatrzyma sam zewnętrznego API, które ignoruje anulowanie.
Przećwiczysz
- Ograniczyć liczbę jednocześnie trwających operacji
- Zachować kolejność wyników
- Oddzielić błąd jednego elementu od całości
- Obsłużyć anulowanie przez AbortSignal
Przykłady
- mapLimited([20, 5, 10, 1], 2, wait)→ najwyżej 2 aktywne naraz; wyniki w kolejności 0, 1, 2, 3
Testy (3)
Testy przeniesione z reference.test.ts materiału źródłowego (node:test). W przeglądarce działają z tym samym zestawem asercji.
map: limit współbieżności, kolejność i częściowy błąd
let active = 0, max = 0;
const result = await mapLimited([20, 5, 10, 1], 2, async (ms, i) => {
active++; max = Math.max(max, active);
await new Promise(r => setTimeout(r, ms)); active--;
if (i === 2) throw new Error('bad');
return i;
});
assert.equal(max, 2);
assert.deepEqual(result.map(r => r.status === 'fulfilled' ? r.value : 'error'), [0, 1, 'error', 3]);map: puste wejście, synchroniczny wyjątek i walidacja limitu
assert.deepEqual(await mapLimited([], 3, async x => x), []);
assert.equal((await mapLimited([1], 1, () => { throw new Error('sync'); }))[0].status, 'rejected');
await assert.rejects(mapLimited([], 0, async x => x), RangeError);map: abort zapobiega rozpoczęciu kolejnego I/O
const controller = new AbortController(); let calls = 0;
const result = await mapLimited([1, 2, 3], 1, async x => { calls++; controller.abort(); return x; }, controller.signal);
assert.equal(calls, 1);
assert.deepEqual(result.map(r => r.status), ['fulfilled', 'rejected', 'rejected']);Powiązane pytania
Źródło: AI & Agents — ćwiczenia praktyczne — Autorskie ćwiczenie z programu nauki, nie potwierdzone zadanie rekrutacyjne.