install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/js-observer-pattern" ~/.claude/skills/intense-visions-harness-engineering-js-observer-pattern-d3c891 && rm -rf "$T"
manifest:
agents/skills/codex/js-observer-pattern/SKILL.mdsource content
JS Observer Pattern
Notify subscribers automatically when an observable object's state changes
When to Use
- Multiple parts of the app need to react to the same event without coupling the emitter to its consumers
- Implementing event systems, reactive UI updates, or real-time data feeds
- Decoupling data sources from their consumers
Instructions
- Create an observable with an
array andobservers
/subscribe
/unsubscribe
methods.notify - Call
whenever the observable's state changes — it invokes all subscribed callbacks.notify(data) - Always provide
— failing to unsubscribe causes memory leaks in long-lived apps.unsubscribe - In browser environments, prefer native
orEventTarget
(Node.js) over hand-rolled implementations.EventEmitter
class Observable { constructor() { this.observers = []; } subscribe(fn) { this.observers.push(fn); return () => this.unsubscribe(fn); // return cleanup function } unsubscribe(fn) { this.observers = this.observers.filter((obs) => obs !== fn); } notify(data) { this.observers.forEach((fn) => fn(data)); } } const store = new Observable(); const cleanup = store.subscribe((data) => console.log('Received:', data)); store.notify({ type: 'UPDATE', payload: 42 }); cleanup(); // unsubscribe
- Return a cleanup/unsubscribe function from
— consumers call it to remove the handler.subscribe
Details
The Observer pattern (also called pub/sub) separates the emitter (subject/observable) from its consumers (observers/subscribers). This decoupling is fundamental to event-driven architectures, reactive state systems, and streams.
Trade-offs:
- If observers are not unsubscribed, the observable holds references to them — memory leak risk in SPAs
- Cascade updates — one observable notifying many observers can cause complex update chains that are hard to trace
- No guaranteed delivery order unless explicitly enforced
- Debugging is harder than direct calls — add logging in
during developmentnotify()
When NOT to use:
- When only one consumer exists — a direct callback is simpler
- When the update sequence matters and subscribers need to be ordered — use a queue or middleware chain instead
- For synchronous, predictable data flow — use signals or reducers
Source
https://patterns.dev/javascript/observer-pattern
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.