How to play sounds asynchronuously, but themselves in a queue?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If sounds should load asynchronously but still play one after another in order, you need a queue and a single playback coordinator. The coordinator's job is simple: enqueue requests immediately, but start the next sound only when the current one finishes.
Separate Loading From Playback Order
The common mistake is to treat asynchronous loading as permission for overlapping playback. Those are different concerns.
A good design has two parts:
- asynchronous loading or preparation of audio assets
- one serialized playback queue
That way the UI stays responsive, but the user still hears the sounds in order.
Queue-Based Design
A first-in, first-out queue is usually enough.
Each enqueue call returns immediately, but only one sound plays at a time.
Why This Works
The queue preserves ordering, and the ended event is the trigger that releases the next item.
You do not need to block the main thread while waiting for a sound to finish. You only need a clear rule that says: no new playback starts until the current sound signals completion.
Handling Preloading
If file loading is slow, you can preload audio objects or decoded buffers before enqueueing them. The queue concept stays the same.
Then your queue can hold prepared audio objects instead of raw URLs.
Preventing Overlap and Reentrancy Bugs
The isPlaying flag matters. Without it, two enqueue calls that happen close together may both decide to start playback, which defeats the queue.
The rule should be:
- enqueue is always safe
- playback is started only by the coordinator
- completion triggers the next dequeue
That single-owner pattern keeps the logic predictable.
A More General Pattern
This design is not specific to browser audio. The same idea applies in mobile apps, game engines, and desktop audio systems:
- one queue
- one active item
- one completion callback
- start the next item only from the completion path
The audio API changes, but the queueing logic stays the same.
Useful Extensions
Real systems often add features such as:
- priority sounds that jump ahead in the queue
- cancellation of pending sounds
- separate queues for music and effects
- a maximum queue length to avoid unbounded buildup
Those are extensions to the same core architecture.
Common Pitfalls
A common mistake is starting playback directly in every asynchronous callback. That makes completion order determine playback order, which is often wrong.
Another mistake is forgetting to guard the "already playing" state, which allows accidental overlap.
Developers also often tie the queue to loading completion instead of explicit enqueue order. If preserving request order matters, the queue should own that ordering explicitly.
Summary
- Queue the sound requests immediately, but let only one coordinator start playback.
- Use a single active sound and start the next one on completion.
- Keep asynchronous loading separate from playback order.
- Guard against reentrancy with an
isPlayingor equivalent state flag. - The same queue pattern works across web, mobile, desktop, and game audio APIs.

