BugHunt

Async bugs and race conditions in JavaScript

A missing await, results in the wrong order, and updates that overwrite each other under load.

14 free challenges14 JavaScript

What is async and race condition?

Code that assumes work has finished when it has not. The symptom is a Promise where a value should be, results arriving in an unexpected order, or state that is correct with one user and wrong with several.

Why it happens

An async function always returns a promise, so forgetting a single await hands the promise itself onward. `return somePromise` inside a try block escapes before it can reject, so the catch never runs. And every await is a point where other code can run — if you read a value, await, then write it back, anything that ran in the gap is silently overwritten.

How to recognise it

  • "[object Promise]" or typeof 'object' where a value was expected.
  • It works with one item and breaks with several.
  • Output order changes between runs.
  • A try/catch around async work never catches anything.

Errors and symptoms this causes

  • [object Promise] in output
  • value is undefined after await
  • results in wrong order
  • try/catch does not catch async error
  • UnhandledPromiseRejection

How to fix it

Await everything that returns a promise, and use Promise.all when you need every result rather than the first. Never hold a copy of shared state across an await — read and write without yielding in between. Test concurrency with concurrent input; a sequential test cannot find a race.

Practise async and race conditions

Working code with one bug in it. Find it, fix it in the browser, and see the explanation. No account needed.

javascriptEasy
Helper function returning undefined

getName(id) should resolve to the loaded user's name, so getName(1) gives "user1".

Async race condition

javascriptHard
Function returning undefined prematurely

delayedDouble(n) should asynchronously resolve to n doubled, e.g. delayedDouble(5) eventually resolves to 10.

Async race condition

javascriptHard
System allowing duplicate reservations

bookSeats(n) handles n concurrent booking requests for a single remaining seat and returns how many bookings succeeded. It should never exceed 1.

Async race condition

javascriptHard
Expensive database queries duplicating

countLoads(n) makes n concurrent calls to a cached loader and returns how many times the expensive load actually ran. It should always be 1.

Async race condition

javascriptHard
High-traffic vote counters returning low totals

tallyVotes(votes) should add up every vote, so tallyVotes([1, 2, 3, 4]) returns 10.

Async race condition

javascriptHard
Errors bypassing the catch block

safeDivide(a, b) should return a / b, or -1 when the division fails. safeDivide(10, 0) should return -1.

Async race condition

javascriptHard
Reducer outputting invalid strings

sumAsync(nums) should add up values fetched asynchronously, so sumAsync([1, 2, 3]) returns 6.

Async race condition

javascriptHard
Sequential data arriving out of order

labelAll(items) should return the names in the same order they were passed in, regardless of how long each one takes.

Async race condition

javascriptHard
Process completes before data arrives

doubleAll(nums) should resolve to a list with every number doubled.

Async race condition

javascriptMedium
Array contains pending operations

collectNames(ids) should resolve every name and report the count and the type of the first entry, so collectNames([1,2]) gives "2-string".

Async race condition

javascriptMedium
API aggregator dropping responses

loadAll(ids) should load every id and return all the results as an array, so loadAll([1, 2, 3]) returns [10, 20, 30].

Async race condition

javascriptMedium
Delayed function returning undefined

doubleLater(value) should resolve to double the value after a short delay, so doubleLater(4) gives 8.

Async race condition

javascriptMedium
Total calculation logs object instead of value

sumDelayed(nums) should add up numbers that each arrive asynchronously, resolving to the total.

Async race condition

javascriptMedium
Array mapping returns empty objects

wordLengths(words) should resolve to a list of each word's length.

Async race condition

Stuck on your own code?

Paste it into the visualizer and watch it run line by line, with every variable at every step. Free, and it runs in your browser.

Other bug patterns