The Observer Pattern lets one or more "observer" objects automatically react whenever a "subject" object's state changes — the foundational idea behind DOM events, reactive state libraries, and much of modern UI programming.
1The Observer Pattern | JavaScript Tutorial - In-Depth Guide Part 1
In the Observer Pattern, a 'subject' maintains a list of 'observers' and notifies all of them whenever its state changes, without needing to know anything specific about what each observer does.
class Subject {
observers = [];
subscribe(observer) { this.observers.push(observer); }
notify(data) { this.observers.forEach((obs) => obs.update(data)); }
}Subjects and Observers
2The Observer Pattern | JavaScript Tutorial - In-Depth Guide Part 2
Each observer implements a common interface (like an 'update' method) so the subject can notify any of them identically, regardless of what each one actually does in response.
const loggingObserver = { update: (data) => console.log('Changed:', data) };
const uiObserver = { update: (data) => renderUI(data) };
subject.subscribe(loggingObserver);
subject.subscribe(uiObserver);A Common Observer Interface
3The Observer Pattern | JavaScript Tutorial - In-Depth Guide Part 3
A production-quality implementation also supports unsubscribing, so an observer that's no longer needed (like a removed UI component) can stop receiving notifications.
class Subject {
observers = [];
subscribe(observer) {
this.observers.push(observer);
return () => { // returns an unsubscribe function
this.observers = this.observers.filter((o) => o !== observer);
};
}
}Supporting Unsubscribe
4The Observer Pattern | JavaScript Tutorial - In-Depth Guide Part 4
The browser's native DOM event system ('addEventListener') is itself a real-world implementation of the Observer Pattern: elements are subjects, and registered listener functions are observers.
// This IS the Observer Pattern:
button.addEventListener('click', handleClick); // subscribe
button.removeEventListener('click', handleClick); // unsubscribeDOM Events Are Observer Pattern
5The Observer Pattern | JavaScript Tutorial - In-Depth Guide Part 5
Reactive state libraries (like those behind modern frontend frameworks) use the Observer Pattern internally: a piece of state is the subject, and UI components that read it are observers automatically re-rendered when it changes.
// Conceptually similar to what a reactive state library does internally:
const state = createObservableState({ count: 0 });
state.subscribe((newState) => rerenderComponent(newState));Powering Reactive UI Libraries
6Step-by-Step Breakdown
In the Observer Pattern, a 'subject' maintains a list of 'observers' and notifies all of them whenever its state changes, without needing to know anything specific about what each observer does.
Each observer implements a common interface (like an 'update' method) so the subject can notify any of them identically, regardless of what each one actually does in response.
Checkpoint: Do all observers subscribed to the same subject need to react to a notification in exactly the same way?
- →Yes, every observer must implement identical behavior
- →No, each observer can react however it needs to
A production-quality implementation also supports unsubscribing, so an observer that's no longer needed (like a removed UI component) can stop receiving notifications.
The browser's native DOM event system ('addEventListener') is itself a real-world implementation of the Observer Pattern: elements are subjects, and registered listener functions are observers.
Checkpoint: Is the DOM's addEventListener/removeEventListener mechanism an example of the Observer Pattern?
- →Yes, elements are subjects and listeners are observers
- →No, they are conceptually unrelated
Reactive state libraries (like those behind modern frontend frameworks) use the Observer Pattern internally: a piece of state is the subject, and UI components that read it are observers automatically re-rendered when it changes.
Next, we'll explore 'Publish / Subscribe'.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Use the Observer Pattern to Keep ARIA Live Regions in Sync with State Changes
Subscribing a dedicated 'accessibility announcer' observer to a state subject ensures that whenever relevant state changes (like a new notification arriving), the corresponding ARIA live region is updated consistently, in the same place, regardless of how many other UI observers also react to that same state change.
SEO Implications
- 1
No Direct SEO Effect
The Observer Pattern is an application-architecture concept; SEO relevance is limited to enabling more maintainable, bug-resistant reactive UI code.
Best Practices
Always Provide and Use an Unsubscribe Mechanism
Without it, subjects accumulate references to observers that should have been removed, creating a memory leak pattern identical to forgotten event listeners.
Keep the Observer Interface Simple and Consistent
A single, uniform method (like update()) that every observer implements keeps the subject's notification logic simple and lets observers be added/removed freely without special-casing.
Frequent Bugs
A subject accumulates subscribed observers indefinitely because unsubscribing was never implemented or never called, causing notify() to grow slower and referenced observers to leak memory over time.
Implement and consistently call an unsubscribe function (or removeObserver method) whenever an observer is no longer needed, such as when a UI component unmounts.
An observer's update() method throws an error, which (depending on implementation) can halt the notify() loop and prevent subsequent observers from being notified at all.
Wrap each observer's update() call in a try/catch inside the notify loop, so one misbehaving observer doesn't prevent others from receiving their notification.
Real-World Examples
A Simple State Container with Subscribable Updates
A small app needed a central piece of state that multiple, independent UI components could subscribe to and automatically react to when it changed.
function createStore(initialState) {
let state = initialState;
const observers = new Set();
return {
getState: () => state,
setState(newState) {
state = { ...state, ...newState };
observers.forEach((obs) => obs(state));
},
subscribe(obs) {
observers.add(obs);
return () => observers.delete(obs);
},
};
}