Recently, I tried to read the source code of Vue (VUe3 is about to come out, vue2 source code has not been read, ashamed of myself), and found that I did not understand the observer and publisher – subscriber model enough, so I wrote to comb and record my ideas.

The difference between the observer model and the publisher-subscriber model

There are some differences between the observer model and the published-subscriber model, and there are some differences, but both aim to improve the traditional notification mechanism and decouple the notifier from the notified. So why is there a difference in the publisher-subscriber model? Is that the latter than the former, one more similar to the existence of the dispatching center, the latter can focus object to manage multiple themes, and there is no direct relationship between observer and publishers, the dispatch center can easily realize the distributed management, this feature allows publishers – subscriber model become more flexible.

Simple implementation of observer and publisher – subscriber patterns

Observer model

class Observer {
    constructor(label) {
        this.label = label
    }
    update() {
        console.log(`update${this.label}`)
    }
}

class Target {
    constructor() { this.observerList = [] } add(observer) { this.observerList.push(observer) } remove(observer) { this.observerList = this.observerList.filter(ob => ob ! == observer) }notify() {
        this.observerList.forEach(ob => {
            ob.update()
        })
    }
}

let tar = new Target()

for (leti = 0; i < 10; I ++) {tar.add(new Observer(I))} tar.notify() print update1 to update10Copy the code

The publisher-subscriber model

class Publisher {
    constructor() {
        this.subscribers = {}
        this.cache = {}
    }

    add(type, fn) {
        if(Object.prototype.toString.call(fn) ! = ='[object Function]') return
        this.subscribers[type]? this.subscribers[type].push(fn) : this.subscribers[type] = [fn]
        return this
    }

    publish(type, theme) {// Store theme information this.cache[type]? this.cache[type].push(theme) : this.cache[type] = [theme]
        let subscribers = this.subscribers[type]
        if(! subscribers || ! subscribers.length) { console.warn('no subscriber in subscribers.')
            return this
        }
        subscribers.forEach(fn => fn.call(this, theme))
        return this
    }

    unbind(type, fn) {
        this.subscribers[type] = this.subscribers[type].filter(item => item ! == fn)return this
    }

    history(type, fn) {
        let cache = this.cache[type] || []
        cache.forEach(item => fn.call(this, item))
        return this
    }
}

let sub1 = data => {
    console.log(`sub1${data}`)}let sub2 = data => {
    console.log(`sub2${data}`)}let sub3 = data => {
    console.log(`sub3${data}`)}let publisher = new Publisher()

publisher.add('click', sub1).add('click', sub2).add('change', sub3)

publisher.publish('click'.'First click').publish('change'.'First change')

publisher.unbind('click', sub1).publish('click'.'Second click').history('click', data => {
    console.log('history'/*** sub1 first click sub2 first click sub3 first change sub2 second clickhistoryFor the first time, clickhistorySecond click ***/Copy the code

As in the above code, the publisher subscriber pattern can perform some custom operations in the dispatch center (equivalent to the publish function in the code), such as throttling, filtering, permission control, and so on.

First write so much ~ have wrong welcome correction ~