When await can block the event loop?
A real case where a small refactor turned async code into an event loop problem.
When await can block the event loop?
Most JS/TS developers know about the event loop. Many know about event loop lag. Some also heard about microtasks.
We also know one simple rule: blocking the event loop is bad.

Symptoms can be different:
- a web page become unresponsive
- HTTP service stop handling requests
- even background workers are restarted by supervisor due to health checks fail
To avoid this, we usually say: don’t do extensive synchronous work, use async code with callbacks or async/await.
This sounds simple, but in real projects, surprises still happen.
This is one case that I had to fix some time ago.
Initial state
We had a worker that processed some array of items as separate job.
For each item it did three things:
- fetched data
- processed it and calculated a hash (synchronously)
- sent the result somewhere else
Simplified code looked like this:
const results = [];
for (const item of items) {
const rawData = await fetchData(item);
const processedItem = processItem(rawData);
results.push(processedItem);
}
await sendResults(results);
Nothing special here:
- data fetching is async
- hashing is synchronous, but quite fast
- the job takes time, but acceptable and can handle plenty of items
- event loop lag is very small
Let’s speed it up
At some point we noticed that number of items was growing. The job started to take more and more time.
It turned out that in most cases we could use cache data and avoid HTTP requests, so we added a simple cache
async function fetchData(item) {
if (cache.has(item.id)) {
return cache.get(item.id);
}
return realHttpCall(item);
}
The interface stayed the same, the logic looked the same, all tests passed and processing time improved a lot.
At first glance — a perfect improvement.
First issues
After a few months the worker started to restart on some jobs. Logs showed that the worker did not respond to the liveness probe. This usually means either a real problem with the probe or event loop lag.
Metrics didn’t clearly show the problem. This also makes sense: when the event loop is blocked, metrics are not sent and Kubernetes just kills the pod.
The bug was not obvious.
When data comes from cache, function return immediately. In practice, this is almost the same as Promise.resolve(value).
This detail is very important, as await always continues execution using the microtask queue. And we need to remember, that all microtasks must be fully executed before the event loop moves to the next macrotask.
The real problem
Because of this improvement, the loop behavior changed. Instead of real IO pauses, we got a long chain of microtasks.
Keep in mind, that we also were calculating hash synchronously. In reality, the loop became to be something like this
const results = [];
for (const item of items) {
const rawData = await Promise.resolve(cachedItem); // immediate resolving
const processedItem = processItem(rawData); // hashing
results.push(processedItem);
}
await sendResults(results);
Each iteration scheduled the next microtask. The event loop did not get a chance to process timers or other requests.
Hashing is fine for 10 items, but for 100,000 items, it caused a long delay.
This situation is called event loop starvation with microtasks.
Even simple sleep with 0 timeout can fix the issue
const sleep = ms => new Promise(r => setTimeout(r, ms));
const results = [];
for (const item of items) {
const rawData = await Promise.resolve(cachedItem);
const processedItem = processItem(rawData);
results.push(processedItem);
await sleep(0);
}
await sendResults(results);
Takeaway
This might be easy to notice in small examples, but in real projects the code is much bigger and spread across many layers.
Today, code is written and refactored very fast, often with the help of AI. In such cases, event loop behavior is rarely considered.
Even a small and unrelated optimization can completely change runtime behavior. After facing such a case once, you become much better at debugging and preventing similar issues.
메타데이터
- post_id
- 54ddff70d9e8
- slug
- when-await-can-block-the-event-loop-54ddff70d9e8
- url
- https://medium.com/@kulikovd/when-await-can-block-the-event-loop-54ddff70d9e8
- canonical_url
- https://medium.com/@kulikovd/when-await-can-block-the-event-loop-54ddff70d9e8
- author_url
- https://medium.com/@kulikovd
- status
- ok
- fetched_at
- 2026-06-22 12:55:45