Publish and subscribe model

The publisk-subscribe pattern, also known as the observer pattern, defines a one-to-many dependency between objects. When an object’s state changes, all dependent objects are notified.

In reality you have to publish and subscribe

The Mid-Autumn Festival is coming, and the moon cakes in the front supermarket have been emptied by all the front bosses. As a result, Li couldn’t buy the moon cakes for his girlfriend. So Li added the wechat of the shop assistant in the supermarket and sent wechat messages every minute to ask whether the moon cakes had arrived (polling).

But in addition to Xiao Li and Xiao Ming, floret and so on, they all want to buy moon cakes, but also every other minute to send wechat to ask, so the salesman little sister quit.

In order to avoid this situation, the new salesgirl little sister wrote down everyone’s phone number (subscription) and told all those who wanted to buy moon cakes that I would take the initiative to inform (release) when the moon cakes arrived.

The role of publish-subscribe

In the example above, there are obvious advantages to using a publish-subscribe model:

  • Polling is avoided, and the salesperson notifies the subscriber at the appropriate time
  • The decoupling between the salesman and the subscriber is established through the phone book. As long as the phone book exists, it doesn’t matter whether the salesman leaves or not.

The first point shows that the publish-subscribe pattern can be used for asynchronous programming as an alternative to passing callbacks.

The second point is that publish-subscribe can replace hard-coded notification between objects, so that one object does not have to call an interface of another object on display.

Publish – subscribe events

In effect, binding event functions to the DOM is a publish-subscribe event.

document.body.addEventListener('click'.() = > {
    console.log(1);
});
document.body.addEventListener('click'.() = > {
    console.log(2);
});
document.body.addEventListener('click'.() = > {
    console.log(3);
});
Copy the code

AddEventListener is actually a process for adding subscriptions. When a user clicks, all subscribers are notified.

We can implement an addEventListener of our own.

let clientList = {};

function myAddEventListener(key, fn) {
    if (clientList[key]) {
        clientList[key].push(fn);
    } else{ clientList[key] = [fn]; }}function myEventTrigger(key) {
    if(! clientList[key]) {// Key does not exist
        return;
    }

    clientList[key].forEach((fn) = > {
        fn();
    });
}

/ / test

myAddEventListener('click'.() = > {
    console.log(1);
});
myAddEventListener('click'.() = > {
    console.log(2);
});
myEventTrigger('click'); / / 1. 2
Copy the code

We have implemented a publish-subscribe function that listens to our own events, but this function cannot be unsubscribed yet.

let clientList = {};

function myAddEventListener(key, fn) {
    if (clientList[key]) {
        clientList[key].push(fn);
    } else {
        clientList[key] = [fn];
    }

    return function unsubscribe() {
        const index = clientList[key].indexOf(fn);
        clientList[key].splice(index, 1);
    };
}

function myEventTrigger(key) {
    if(! clientList[key]) {// Key does not exist
        return;
    }

    clientList[key].forEach((fn) = > {
        fn();
    });
}

/ / test

const unsubscribe1 = myAddEventListener('click'.() = > {
    console.log(1);
});
const unsubscribe2 = myAddEventListener('click'.() = > {
    console.log(2);
});
const unsubscribe3 = myAddEventListener('click'.() = > {
    console.log(3);
});
unsubscribe2();
myEventTrigger('click'); / / 1. 2
Copy the code

We do this by returning the unsubscribe function at subscription time. Now it’s a little bit inconvenient to write it this way and if you’re interested in it you can wrap it up and not expand it.

Publish subscription in Vue3

Vue3 responsiveness is based on a publish-subscribe model.

TargetMap [target][key]; targetMap[target][key] is a Set that stores subscribers. Corresponds to the effect side effect function in Vue3.

// const targetMap = new WeakMap<any, KeyToDepMap>()
// Data structure
{
    targetMap: {
        target: {
            key: [effect, effect]; // Set}}}Copy the code

The track function collects subscriptions, and the trigger function triggers subscription notifications. The effect function establishes a connection between the subscriber and the subscribed object.

const obj = { foo: 1 };
effect(() = > {
    console.log(obj.foo);
    track(obj, TrackOpTypes.GET, 'foo');
});

obj.foo = 2;
trigger(obj, TriggerOpTypes.SET, 'foo');
Copy the code

We can create responses manually, and in Vue the Vue is created automatically by intercepting get and set.

summary

Publish – subscribe benefits

  • Decoupling in time
  • Decoupling between objects

disadvantages

  • Creating a subscriber itself consumes memory for a certain amount of time. After subscribing to a message, the message does not necessarily happen, but the subscriber will always be there
  • The publish-subscribe model can weaken the relationship between objects, but when overused, necessary relationships between objects can be hidden, making it difficult for programs to track, maintain, and understand.