Find Cases
Find the exact JavaScript confusion you are trying to solve.
Search by symptom, topic, difficulty, or real-world problem across guided demos, editable variations, and Node runtime cases.
Promise.all rejects the whole combined promise when one input rejects.
Timers cannot run while the call stack is blocked or microtasks keep draining.
Growing memory usually means retained references, listeners, timers, caches, or large buffers.
Sync execution
Synchronous lines run immediately, top to bottom.
setTimeout 0
A zero millisecond timer still waits for the stack to clear.
Promise before timeout
Microtasks run before timers after the stack clears.
Multiple timers
Timers with the same delay run in the order they were queued.
Nested timeout
A timer created inside a timer waits for another task turn.
Promise inside timeout
Microtasks created by a timer run before the next timer.
Timeout inside promise
A timer created by a microtask joins the timer queue after existing timers.
Blocking loop
Long synchronous work delays every queued callback.
Promise lifecycle
A promise starts pending, then settles once.
Promise rejection
Rejected promises skip success handlers and go to rejection handlers.
then chaining
Returning a value passes it to the next `.then`.
Missing return
If a `.then` callback does not return, the next value is `undefined`.
Error in then
Throwing inside `.then` turns the next promise into a rejection.
Promise.all success
`Promise.all` resolves when every input resolves.
Promise.all fail
`Promise.all` rejects as soon as one input rejects.
async returns promise
An async function always returns a promise.
await behavior
`await` pauses the async function and resumes it in a microtask.
missing await
Without `await`, code keeps going while the promise is pending.
try/catch
A try/catch around `await` catches promise rejections.
sequential await
Awaiting one operation before starting the next makes them sequential.
parallel Promise.all
Start independent promises first, then await them together.
async forEach issue
`forEach` does not await async callbacks.
interval leak
Intervals keep callbacks and captured data alive until cleared.
event listener leak
Listeners can retain component state after the UI is gone.
closure memory hold
Closures keep referenced outer variables alive.
cache growth
Caches need eviction or they grow for the lifetime of the app.
blocking loop
CPU-heavy loops monopolize the main thread.
microtask flood
Too many microtasks can starve timers and rendering.
sequential vs parallel API
Independent API calls are faster when started together.
debounce concept
Debounce resets a timer so only the final burst action runs.
process.nextTick vs Promise
In Node.js, nextTick callbacks run before Promise microtasks.
setImmediate after I/O
Inside an I/O callback, setImmediate usually runs before a zero-delay timer.
EventEmitter listeners are sync
EventEmitter.emit calls listeners immediately on the current stack.
Stream backpressure
When stream.write returns false, wait for drain before writing more.
Unhandled rejection timing
A rejected promise reports as unhandled after the current turn if no catch is attached.
Top-level await blocks importers
A module with top-level await pauses evaluation of modules that import it.
libuv thread pool callback
Some Node work runs off the main thread, but callbacks return to the JS event loop.
AbortController cleanup
Aborting a fetch rejects the pending operation and prevents stale work.
Worker thread offload
Move CPU-heavy work to a worker so the main event loop keeps responding.
AsyncLocalStorage request context
AsyncLocalStorage can preserve request context across async boundaries.
React batched state log
State updates are scheduled, so logging state right after setState can show the old value.
Effect cleanup race
React runs cleanup for the previous effect before the next effect starts.
Stale closure timeout
A delayed callback remembers the values from when it was created.
Fake timers vs promises
Advancing fake timers does not automatically flush every Promise microtask.
requestAnimationFrame vs timeout
requestAnimationFrame is aligned with the browser paint cycle; timers are general tasks.
Debounce vs throttle
Debounce waits for quiet; throttle limits how often work can run.
Fetch abort race
Cancel stale requests so older responses cannot overwrite newer UI state.
WebSocket message task
WebSocket messages arrive as event tasks; they do not interrupt synchronous rendering.
Idle callback background work
requestIdleCallback runs low-priority work only when the browser has spare time.
MutationObserver timing
MutationObserver callbacks run before timers after DOM changes are observed.
React effect cleanup missing
Effects that register timers or listeners must clean them up or old work keeps running after the component is gone.
Next.js server action missing await
A server action can return success before persistence finishes if async work is started but not awaited.
Vitest fake timers and microtasks
Advancing timers is not the same as flushing promise jobs in tests.
Express slow route blocking
CPU-heavy work inside a request handler blocks unrelated requests on the same event loop.
File upload backpressure bug
Ignoring stream backpressure lets upload buffers grow faster than the destination can write.
Redis/cache memory growth
Unbounded in-process caches retain data even when Redis or the database is the real source of truth.
Promise vs Timer
Microtasks run before timers, even when timer delay is 0.
Multiple Timers
Timers are scheduled now, but run later by delay and queue order.
Timer Inside Promise
Where a timer is scheduled changes its place in line.
Blocking Loop Delays Timer
Timers cannot run while the call stack is blocked.
Promise Chain Return
Missing return breaks value flow through .then().
Promise.all
Promise.all waits for all success, but rejects on first failure.
Promise.race vs Promise.any
race settles first; any fulfills first successful promise.
Sequential vs Parallel Await
Sequential awaits add wait time; parallel waits for the slowest request.
Missing Await
Without await, later code continues before the async result is ready.
Async forEach Problem
forEach does not wait for async callbacks.
Uncleared Interval Leak
Intervals keep running and retaining captured memory unless cleared.
Microtask Flood
Too many microtasks can delay timers and make the app feel stuck.
Node queue priority
Node drains process.nextTick before Promise microtasks, then moves through timer, I/O, check, and close phases.
fs.readFile and the thread pool
Async file work leaves the JS call stack, uses libuv, then returns a callback through the I/O queue.
Thread pool saturation
fs, crypto, zlib, and some DNS work share a limited libuv worker pool.
HTTP request with database call
A request handler starts sync, awaits network/database work, then resumes when the promise settles.
Stream pipe with backpressure
Streams move chunks and pause reads when the writable side cannot keep up.
Buffers and encoding
Buffers store bytes; encoding controls how bytes become text.
Memory leak: cache, listener, timer
Long-lived references stop garbage collection even when a request is finished.
Large JSON parse blocks requests
CPU-heavy synchronous work blocks the event loop even if your server uses async I/O.
Promise.all vs allSettled
Promise.all fails fast; allSettled keeps every result.
Centralized async errors
Rejected route promises need a centralized path to logging and response handling.
CommonJS module cache
CommonJS modules execute once, then require returns the cached exports.
Validation and rate limiting
Reject unsafe input early and limit abusive request bursts before expensive work starts.
Testing async timers
Timer helpers and Promise microtasks are different things in tests.
Graceful shutdown
Production Node apps should stop accepting new work, finish active requests, then close resources.
Interview: explain the event loop
A strong event-loop answer connects stack, queues, async APIs, and real production consequences.
Error-first callback flow
Classic Node callbacks pass errors first so success code should only run after the error branch is checked.
setInterval drift under load
Intervals schedule ticks, but callbacks cannot run while the event loop is blocked.
nextTick starvation
A recursive process.nextTick loop can starve Promise callbacks, timers, and I/O.
setImmediate inside I/O
Inside an I/O callback, setImmediate is usually reached before a newly scheduled timer.
Promise.race request timeout
Promise.race settles with the first promise, but slower work may still continue unless you cancel it.
Promise.any fallback
Promise.any ignores rejections until one promise fulfills, then only fails if all reject.
readFileSync blocks server
Synchronous filesystem calls block the event loop and delay every other request in the process.
DNS lookup and worker pressure
Some DNS work can share worker-pool capacity with fs, crypto, and zlib tasks.
zlib compression uses workers
Compression is async, but it can still saturate libuv workers and delay other pool users.
Full read vs stream memory
Reading a whole file allocates the full payload; streaming processes chunks and keeps memory flatter.
Stream error handling
Streams can fail after work starts, so pipeline-style error handling is safer than manual pipe chains.
Buffer base64 payload
Base64 is text that represents bytes; converting back to a Buffer is required before binary processing.
Worker thread for CPU work
Worker threads move CPU-heavy JavaScript off the main event loop.
Cluster request distribution
Multiple Node processes can share traffic so one blocked process does not stop every request.
Unhandled rejection policy
Unhandled promise rejections must be logged and handled deliberately instead of silently ignored.