Przejdź do treści
Jobless Busters
Z testamiŚrednia20–30 min

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.

  • 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
  • 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

JavaScript
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

JavaScript
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

JavaScript
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']);

Źródło: AI & Agents — ćwiczenia praktyczne — Autorskie ćwiczenie z programu nauki, nie potwierdzone zadanie rekrutacyjne.

JavaScript · uruchamiany w Web Workerze w przeglądarce

Tab wcina · Esc, a potem Tab, opuszcza edytor · ⌘/Ctrl + Enter uruchamia testy · Twój kod jest zapisywany w tej przeglądarce.

Uruchom testy, żeby sprawdzić rozwiązanie. Gotowych testów: 3.

Utknąłeś? Podpowiedzi idą od ogólnych do konkretnych.

Najpierw spróbuj naprawdę — rozwiązanie najwięcej daje, gdy już trochę się namęczysz.