Javascript async code only works when debugging
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
If asynchronous JavaScript only seems to work when you step through it in a debugger, you almost certainly have a timing bug. Breakpoints slow the event loop down and accidentally hide race conditions, missing await calls, or lifecycle mistakes that still exist when the code runs at full speed.
Why the Debugger Changes the Result
A debugger changes timing. Promises have more time to settle, DOM updates finish before dependent code runs, and async initialization may complete before the rest of the program touches shared state.
That means the debugger is not fixing the bug. It is acting like temporary synchronization.
A simple example:
When this runs normally, config is often still undefined. When you single-step in the debugger, the pause may give init() enough time to finish first, which makes the bug appear to disappear.
Make the Dependency Explicit
The correct fix is to express the dependency in code:
Now the program says exactly what it means: the app must not start until initialization is complete.
Do Not “Fix” It With setTimeout
One of the most common bad fixes is to add an arbitrary delay:
This is not synchronization. It is just guessing how much time the async work might need.
It may appear to work:
- on one machine
- with one network speed
- in one browser
- under one CPU load
and then fail elsewhere.
If the real problem is ordering, the right tools are:
- '
await' - returned promises
- explicit initialization state
- a shared in-flight promise
Not a sleep disguised as a fix.
Return Promises From Helper Functions
Another frequent source of “works only in the debugger” bugs is helper functions that start async work but do not return the promise.
Wrong:
Better:
Returning the promise is what gives the caller a real way to wait for the work to finish.
Use a Shared Initialization Promise
If multiple parts of the program depend on the same startup task, a shared initialization promise often solves the race cleanly:
This avoids multiple overlapping startup paths that race against each other.
Log Phase Transitions, Not Just Values
When debugging async problems, logs are most useful when they tell you what finished before what.
That timeline often reveals the bug faster than stepping every line manually.
Unhandled rejection logging can also expose failures that breakpoints accidentally mask:
Common Pitfalls
The biggest mistake is “fixing” the bug with setTimeout instead of correcting the missing dependency edge.
Another issue is starting async work inside a helper but forgetting to return the promise, so callers cannot coordinate with it.
People also often mutate shared global state from multiple async paths without one clear owner or initialization contract.
Finally, debugger success is not proof of correctness. If the program only works when slowed down, the real bug is still present.
Summary
- Async JavaScript that only works while debugging usually has a timing or ordering bug.
- Breakpoints hide races by slowing down surrounding work.
- Use
await, returned promises, or explicit lifecycle control instead of arbitrary delay hacks. - Shared initialization promises are a clean way to coordinate startup work.
- Log phase transitions and unhandled rejections to make hidden async failures visible.
Related reading
- Javascript, async, lock?
- JavaScript Asynchronous method in while loop
- JavaScript asynchronous race condition
- Javascript background loop
- JavaScript Calculate the nth root of a number
- Javascript call() & apply() vs bind()?
- JavaScript callbacks for asynchronous functions is there any pattern to differentiate between return value and exception?
- Javascript console.log in an iOS UIWebView
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.