TGViewer
Настоящий JavaScript Настоящий JavaScript @true_js · 5.89K subscribers
Post #3625 310
⁣AbortSignal.timeout() убивает Worker до старта: неочевидные race condition при вложенных сигналах

Передаёшь AbortSignal в Worker через postMessage и ждёшь abort как гарантию отмены? Типичная ловушка: сигнал с таймаутом стартует в момент создания, а не когда Worker его получает. Результат — Worker грузится дольше таймаута и получает уже aborted: true, не выполнив ни строчки кода.

Таймаут живёт в main thread, Worker получает мёртвую копию

const controller = new AbortController();
const timeoutSignal = AbortSignal.timeout(5000);
const combined = AbortSignal.any([controller.signal, timeoutSignal]);
worker.postMessage({ type: 'start', signal: combined });


Таймер из AbortSignal.timeout() не Transferable. Сигнал передаётся как структурированная копия состояния, но оригинал остаётся в main thread. Если таймаут срабатывает после передачи — Worker никогда не узнает об этом. Memory leak гарантирован, так как замыкание с обработчиком abort не очищается.

Нельзя сбросить сработавший сигнал

Когда AbortSignal.timeout() abort'нул внешний сигнал через AbortSignal.any(), контроллер становится мёртвым навсегда:

controller.signal.addEventListener('abort', () => console.log('aborted'));
timeoutSignal.dispatchEvent(new Event('abort'));
controller.abort(); // 0 реакций, контроллер уже не активен


Это race condition, который не ловится без логов: ты пытаешься вызвать controller.abort() позже, но сигнал уже в состоянии aborted: true от таймаута.

Практический совет для Workers

Создавай AbortSignal.timeout() прямо внутри Worker, а не передавай снаружи:

// Внутри Worker
self.onmessage = ({ data }) => {
const timeout = AbortSignal.timeout(5000);
if (data.signal.aborted) return;
timeout.addEventListener('abort', () => controller.abort());
};


Перед стартом работы явно проверяй if (signal.aborted) return. Используй один центральный AbortController для всех вложенных сигналов вместо цепочек через AbortSignal.any(). Это снижает риск невидимых race condition при комбинировании таймаутов.

Вывод: AbortSignal.timeout() хорош для простых таймеров в одном потоке, но при передаче в Workers и комбинировании сигналов требует явной проверки состояния и изоляции создания таймаута внутри получателя.
More from @true_js
  1. Oct 3, 2026Post #3963
  2. Oct 2, 2026😅 Айтишник отправил в одну компанию три одинаковых резюме и только одно дошло до финала О…
  3. Oct 2, 2026Post #3961
  4. Oct 2, 2026🤣 Правильно расставленные приоритеты в моей жизни би лайк: 💥 xCode Journal
  5. Oct 1, 2026🤯 Люди взбунтовались против «пыточной для ИИ» На GitHub заметили открытый проект AI Tortu…
  6. Oct 1, 2026День в Заонежье начинается ещё в дороге. Мы встретим вас в аэропорту или на вокзале. Дальш…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →