Your Sunday, upgraded. Free live AI class · 5 PM ISTReserve your seat
PROGRAMMING LANGUAGES

Read the JavaScript Event Loop through One Slow Click Handler

A frozen button is often an event-loop problem, not a slow computer. Follow one click through the call stack, task queue and microtasks to see why the page stops responding and how to fix it.

On this page

The core idea

JavaScript in the browser runs your code on a single main thread. The event loop takes one task at a time, such as a click handler or a timer callback, and runs it to completion. Only when the call stack is empty does the browser get a chance to render or handle the next event. Promise callbacks are microtasks: they run after the current task finishes but before the browser renders. A long synchronous loop, or a long chain of microtasks, therefore blocks painting and input just as surely as a heavy calculation.

A practical approach

Step 1

Reproduce the freeze with the browser's Performance panel recording. Look for a long task (over 50 milliseconds) and expand it to find which function is running.

Step 2

Identify whether the work is synchronous computation, a large DOM update or a flood of microtasks. Each needs a different fix.

Step 3

For heavy computation, move it off the main thread with a Web Worker, or split it into chunks and yield between them with setTimeout or scheduler.yield where supported.

Step 4

For large DOM updates, build content in a fragment and insert it once, or render only the visible rows of a long list.

Step 5

Give immediate feedback before the expensive work starts: disable the button and show progress, then let the browser render by yielding once before continuing.

Worked example

A catalogue page filters 10,000 course items when the learner types in a search box. Each keystroke runs a synchronous filter, sorts the results and rebuilds the whole list, so typing feels stuck. Recording the interaction shows 300-millisecond long tasks. Debouncing the input, filtering on a precomputed lowercase index and rendering only the first 24 results reduces each task to a few milliseconds, and the input stays responsive.

A mistake to avoid

Do not wrap slow code in a Promise and assume it now runs in the background. new Promise(resolve => { heavyWork(); resolve(); }) still runs heavyWork synchronously on the main thread. Promises organise asynchronous results; they do not create threads.

Try it yourself

Write a button handler that counts to 500 million in a loop and updates a label. Observe that the label never shows intermediate values. Then rewrite it to process the count in chunks with a yield between them, and compare the two in the Performance panel.

Your implementation checklist

  • I can find long tasks in a performance recording
  • Expensive work is chunked, debounced or moved to a worker
  • Large DOM changes are batched or virtualised
  • Users get feedback before slow work begins
  • I do not expect Promises alone to make code non-blocking

Share or cite this guide

Innovate with Ajay Editorial (2026-10-07). Read the JavaScript Event Loop through One Slow Click Handler. https://innovatewithajay.com/blogs/read-the-javascript-event-loop

Editorial approach, sources and corrections

YOUR NEXT CHAPTER

You have the curiosity.
Let’s turn it into capability.

Start with a practical workshop or bring a specific question to Ajay.

Chat with Ajay