Skip to content

web-development-mart/observer-vanillaJs-front

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The Observer Pattern

Comparing the Observer Pattern to addEventListener in vanilla JavaScript is an excellent pedagogical simplification. In fact, addEventListener is one of the most widely used real-world implementations of this pattern.

Pattern Flow

Observer Pattern Flow

1. The Roles

  • The Subject (The Node/Element): In addEventListener, the DOM element or Node (like a button or window) acts as the Subject. It is the "Broadcaster" that holds the potential for an event (like a 'click') to happen.

  • The Observers (The Callback Functions): The functions registered in the observers array act as the Observers. Each waits for the Subject to trigger a change and then executes its logic. In this demo, there are three observers:

    • notifyUser() — Shows a browser alert to the user
    • logTransaction() — Logs the transaction timestamp to the console
    • updateStatus() — Updates the UI status badge on the page

2. The Communication Lifecycle

  • Subscription: When you call element.addEventListener('click', callback), you are performing the Registration phase. In this demo, the observers are registered in an array of objects, each containing the observer's name, function reference, and a subscribed boolean flag:

    const observers = [
        { name: "notifyUser", func: notifyUser, subscribed: true },
        { name: "logTransaction", func: logTransaction, subscribed: true },
        { name: "updateStatus", func: updateStatus, subscribed: true },
    ]
  • Notification: When the purchase button is clicked, the handlePurchaseClick() function iterates through the observers array with a 750ms educational delay between each. For each observer, it checks the subscribed flag—if true, the observer's function executes; if false, it is skipped.

  • Unsubscription: In the standard DOM API, you use element.removeEventListener('click', callback) to detach an observer. In this demo, unsubscription is simulated using toggle buttons that flip each observer's subscribed flag to false, allowing the Subject to skip them during notification without removing them from the registry. This is crucial for Memory Management; if you don't detach listeners in production code, you risk the "Lapsed Listener Problem," where objects stay in memory longer than necessary.

3. Why the Comparison Works

  • Decoupled Communication: The button doesn't need to know what your function does (e.g., whether it saves data to a database or just changes a CSS color). It only knows that it must call that function when the event happens.

  • One-to-Many Dependency: You can attach five different addEventListener calls to the same single button. When clicked, that one Subject notifies all five Observers simultaneously. In this demo, the single purchase button notifies three observers sequentially (with delays for visibility).

A Small Technical Nuance

While addEventListener is a perfect conceptual match, modern JavaScript architecture often moves beyond basic events to "Transparent Observation" using Proxy and Reflect. This allows the system to observe changes to data objects directly, rather than waiting for a manual DOM event to fire.

This pattern is a great starting point for understanding how to use the Observer Pattern in real-world JavaScript applications.

Relevance to JavaScript

Event-Driven Architecture: JavaScript relies heavily on this pattern. The addEventListener method in the DOM is the classic implementation (DOM element = Subject, Callback function = Observer).

Asynchronous Handling: It is foundational for handling asynchronous operations, where the result isn't available immediately.

Reactive Programming: Modern libraries (like RxJS) and frameworks (like Vue.js or React's state management) are built upon advanced versions of this pattern.


Questions for Students

After exploring the interactive demo, answer these questions to test your understanding of the Observer Pattern:

1. Unsubscription Behavior

Question: Unsubscribe from Observer 1 (notifyUser) using the toggle button, then click "Purchase Now". What happens differently? Why doesn't the alert appear anymore?

💡 Click to reveal answer

When Observer 1 is unsubscribed, the Subject checks the observer's subscribed status before executing it. Since subscribed is false, the Subject skips that observer entirely and shows "NOT SUBSCRIBED - Skipped execution" instead. The alert doesn't appear because the notifyUser() function is never called, even though it still exists in the observers registry. This demonstrates Dynamic Management - observers can be removed at runtime without breaking the system.

2. Complete Unsubscription

Question: What happens if you unsubscribe from ALL three observers and then click "Purchase Now"? Does the button still work? What does this tell you about the Subject's role?

💡 Click to reveal answer

The button still works perfectly! You'll see messages like "Checking Observer 1...", "NOT SUBSCRIBED - Skipped", etc. The Subject (button) still iterates through its registry and attempts to notify all observers, but none execute because they're all unsubscribed. This demonstrates Decoupled Communication - the Subject doesn't care whether observers actually do anything; it just maintains the registry and attempts notification. The Subject's responsibility is to broadcast, not to guarantee execution.

3. The 750ms Delay

Question: The demo includes a 750ms delay between each observer notification. What would happen if we removed this delay? Why was it added? How does this relate to real-world addEventListener?

💡 Click to reveal answer

Without the delay, all three observers would execute almost instantly (within milliseconds), making it impossible to see the step-by-step notification process. The delay is purely educational - it lets students visually follow how the Subject iterates through its registry and notifies each observer sequentially. In real-world JavaScript with addEventListener, there is NO artificial delay - all listeners execute synchronously and nearly instantaneously when the event fires. The delay helps reveal the internal mechanism that would otherwise be invisible.

4. Observer Independence

Question: Observer 1 shows an alert (which blocks execution until you click "OK"), Observer 2 logs to console, and Observer 3 updates the UI. If Observer 1 is subscribed, why do Observers 2 and 3 have to "wait" for you to close the alert before they execute?

💡 Click to reveal answer

JavaScript is single-threaded, meaning only one operation can execute at a time. The alert() function is blocking - it pauses all JavaScript execution until the user clicks "OK". Even though the observers are independent and don't know about each other (Decoupled Communication), they still execute on the same thread sequentially. In real applications, you'd avoid blocking operations like alert() and use non-blocking alternatives (like toast notifications) to maintain responsiveness. This demonstrates why asynchronous patterns and non-blocking code are important in JavaScript.

5. Adding a New Observer

Question: How would you add a 4th observer called sendEmail() that logs "Email sent!" to the console? What changes would you need to make to the code, and where would you need to modify both the HTML and JavaScript files?

💡 Click to reveal answer

You would need to make these changes:

JavaScript (script.js):

  1. Create the observer function:

    const sendEmail = () => {
        console.log("📧 Email sent!")
        logActivity("📧 <strong>Observer 4:</strong> sendEmail() executed", "primary")
    }
  2. Add it to the observers array:

    const observers = [
        { name: "notifyUser", func: notifyUser, subscribed: true },
        { name: "logTransaction", func: logTransaction, subscribed: true },
        { name: "updateStatus", func: updateStatus, subscribed: true },
        { name: "sendEmail", func: sendEmail, subscribed: true }  // NEW!
    ]

HTML (index.html): 3. Add a toggle button in the subscription controls section:

<div class="col-md-3">
    <button id="toggle-observer-4" class="btn btn-success btn-sm w-100">
        ✓ Observer 4: Subscribed
    </button>
</div>
  1. Update the JavaScript to reference the new button in the toggleButtons array.

This demonstrates the extensibility of the Observer Pattern - new observers can be added without modifying the Subject or other observers!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages