Skip to content

feat!: auto-disconnect observer after wait() resolves #50

Description

@untemps

Summary

⚠️ Breaking change — this is the intentional fix that accompanies bug #36. Listed separately as a breaking change because it alters the observable contract of isObserving and instance reuse patterns.

Make wait() automatically disconnect the internal observer and clear all internal state as soon as the promise resolves, without requiring the caller to call clear() manually.

Current behaviour (bug)

After wait() resolves, isObserving returns true and the MutationObserver keeps running. Callers who reuse the instance must call clear() explicitly before the next wait() or watch(). Failing to do so is not surfaced as an error.

Proposed behaviour

const obs = new DOMObserver()
const { node } = await obs.wait('#foo')
console.log(obs.isObserving)   // false — auto-cleared

The observer is disconnected, the timeout is cleared, and all internal state is reset to the same state as a freshly constructed instance.

Breaking scenarios

1. Code that assumes isObserving is true after resolution

Unlikely in practice, but code that branches on obs.isObserving immediately after await obs.wait(...) would change behaviour.

2. Code that calls clear() after wait() as a precaution

Double-calling clear() is safe (it is idempotent), so this is not technically broken — it just becomes a no-op.

3. Code that relies on the stale timeout firing after resolution

Currently, if wait(target, { timeout: 5000 }) resolves at 100ms, the timer fires at 5000ms and calls this.clear(). Some code might inadvertently depend on this cleanup being deferred. After this change, cleanup happens at 100ms.

Implementation

In wait(), change settle():

const settle = (value: WaitResult) => {
    cleanup()       // remove abort listener
    this.clear()    // disconnect observer, clear timeout — NEW
    resolve(value)
}

Migration

No code changes needed for most callers. The pattern await obs.wait(...); obs.clear() continues to work (second clear() is a no-op). Code that explicitly checked obs.isObserving === true after wait() would need updating.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions