# Async lifecycle (MozPromise & shutdown) — dom/media review guidance > This covers the async-object lifetime idioms that are the most common source of > media use-after-free and hangs. ## General patterns - **A `MozPromise` is resolved OR rejected exactly once, on every path.** Check every early-return, error, and cancel path — a path that returns without settling the promise leaks/hangs the waiter; a path that can settle it twice is a bug. - **`Then` runs on the intended thread.** The resolve/reject callback is dispatched to the queue/thread the code assumes, and it only touches state that is valid on that thread. - **Request holders are tracked and disconnected.** A pending `->Then(...)` tracked by a `MozPromiseRequestHolder` (or a `MozPromiseHolder` on the producer side) must be `Disconnect()`/`DisconnectIfExists()`-ed during teardown, so a late resolution does not fire a callback into a destroyed object. - **No raw `this` in a promise callback.** A `Then` callback (or lambda) that captures `this`/a raw pointer without holding a strong `RefPtr` is a use-after-free the moment it resolves after the owner is gone. Either hold a strong ref or disconnect the request on teardown. - **Shutdown ordering.** Nothing is dispatched or started after `Shutdown()`; in-flight async work is completed or cancelled before the object tears down; a shutdown blocker is not satisfied until that teardown actually finishes. ## dom/media specifics - **Promise-chained pipeline.** Decoders, demuxers, and the MDSM chain `MozPromise`s heavily (Init, Decode, Seek, Flush, Shutdown). A chain that can be abandoned mid-flight (seek/flush/error/shutdown) must disconnect its request holders so a stale resolution does not run against a reset or destroyed stage. - **`MediaShutdownManager` / shutdown blockers.** The MDSM/decoder registers a shutdown blocker; confirm the blocker is only released after the async teardown (flushing queues, shutting down the decoder, releasing the task queue) completes — not on a happy-path callback that may not run. - **Init vs Shutdown ordering.** A pending Init/Decode promise that resolves after a Shutdown has begun must be handled (disconnected or made a no-op), not allowed to touch torn-down state. - **Error paths settle the promise.** On a decode/demux error, the corresponding promise is rejected (not dropped) so the state machine does not hang waiting. - **One in-flight request per resource.** Do not issue a new request for a resource (e.g. `RequestVideoData`/`RequestAudioData` for a track) while a prior request for the same resource is still pending. - **Resolve waiting/retry promises on every transition.** A "waiting for data" promise must be resolved on every transition to data-available (and any paired start-time state cleared with it); a missed resolution is a permanent stall, not just a delay.