Concurrency patterns
JavaScript — однопоточный, но I/O-конкурентный; грамотное управление параллелизмом (семафоры, пулы, очереди с backpressure) — то, что чётко отличает Senior от Mid на техническом собесе.
// Semaphore — ограничение параллелизмаclass Semaphore { #permits; #queue = []; constructor(permits) { this.#permits = permits; }
acquire() { if (this.#permits > 0) { this.#permits--; return Promise.resolve(); } return new Promise(resolve => this.#queue.push(resolve)); }
release() { if (this.#queue.length > 0) { this.#queue.shift()(); // пробуждает следующего ожидающего } else { this.#permits++; } }}
const sem = new Semaphore(3); // не более 3 параллельных запросовasync function limitedFetch(url) { await sem.acquire(); try { return await fetch(url); } finally { sem.release(); }}// p-limit паттерн: concurrency-limited map (аналог p-limit npm)async function pMap(items, fn, { concurrency = Infinity } = {}) { const results = new Array(items.length); let index = 0;
async function worker() { while (index < items.length) { const i = index++; results[i] = await fn(items[i], i); } }
await Promise.all( Array.from({ length: Math.min(concurrency, items.length) }, worker) ); return results;}
// Не более 5 одновременных fetchconst data = await pMap( urls, url => fetch(url).then(r => r.json()), { concurrency: 5 });// Async queue с backpressure через async iteratorclass AsyncQueue { #items = []; #resolvers = [];
push(item) { if (this.#resolvers.length > 0) { this.#resolvers.shift()(item); // будим ожидающего consumer-а } else { this.#items.push(item); } }
async *[Symbol.asyncIterator]() { while (true) { if (this.#items.length > 0) { yield this.#items.shift(); } else { yield await new Promise(r => this.#resolvers.push(r)); } } }}
const queue = new AsyncQueue();setInterval(() => queue.push(Date.now()), 100); // producerfor await (const ts of queue) { await processTimestamp(ts); // consumer с автоматическим backpressure}Итог: Concurrency в JS управляется явными паттернами — семафоры, async iterators, Promise-пулы — всё без многопоточности; ключевое отличие Senior: понимание backpressure и ограничения параллелизма.