Ps: this mode to understand the line, I did not write too much, because the code is too much. Tiring, a little bit too much code, I wrote some comments, we slowly look

Meaning that

The publish-subscribe pattern, also known as the observer pattern, defines a multi-dependency relationship between objects. When the state of an object changes, all dependent objects are notified to subscribe before publishing

role

1. Supports simple broadcast communication. When the status of objects changes, the subscribed objects will be automatically notified.

2. It can be used in asynchronous programming as an alternative to the callback function. It can be used in asynchronous programming to subscribe to events after AJ AX.

3. Loose coupling between objects The two objects do not know each other but do not affect communication. When a new subscriber appears, the published code does not need to change

4. Vue and React transfer values across components

Examples of life

Such as small red recently after a pair of shoes on taobao, but after it contact to the seller, only to find that this pair of shoes sold out, but the little red for this pair of shoes and like it very much, so contact the seller, ask the seller when the purchase is made, and the seller told her, have to wait a week before purchase is made, and the seller told the little red, if you like, you can collect our shop, I will inform you when the goods are available, so Xiao Hong collected this shop, but at the same time, Xiao Ming, Floret also like this pair of shoes, also collected the shop; When the goods arrive, they will be informed in turn:

How to implement the publish-subscribe model?

-1. First decide who the publisher is (e.g. the seller above).

-2. Then add a cached list to the publisher to store the callback function to notify the subscription (for example, the buyer above bookmarks the seller’s store, and the seller bookmarks a list of that store).

-3. Finally, publish the message. The publisher iterates through the cache list and triggers the subscriber callback function stored in it.

 var shopObj = {} // Define the publisher
        shopObj.list = [] // Cache a list of subscribed functions
        // Add subscribers
        shopObj.listen = function (key, fn) {
            if (!this.list[key]) {
                this.list[key] = []
            }
            this.list[key].push(fn)
        }
        // Publish the message
        shopObj.trigger = function () {

            / / get the key
            var key = Array.prototype.shift.call(arguments)
            var fns = this.list[key]
            / / determine
            if(! fns || fns.length ==0) {
                return
            }
            for (var i = 0, fn; fn = fns[i++];) {
                // fn.apply(this, arguments)fn(... arguments) } } shopObj.listen('red'.function (size) {
            console.log(` size is${size}`);
        })
        shopObj.listen('black'.function (size) {
            console.log(` size is${size}`);
        })
        / / the little red
        shopObj.trigger('red'.42)
        / / Ming
        shopObj.trigger('black'.43)
        // One encapsulation
        var event = {
            list: [].listen: function (key, fn) {
                if (!this.list[key]) {
                    this.list[key] = []
                }
                this.list[key].push(fn)
            },
            trigger: function () {

                / / get the key
                var key = Array.prototype.shift.call(arguments)
                var fns = this.list[key]
                / / determine
                if(! fns || fns.length ==0) {
                    return
                }
                for (var i = 0, fn; fn = fns[i++];) {
                    // fn.apply(this, arguments)fn(... arguments) } } }// Unsubscribe
        event.remove = function (key, fn) {
            var fns = this.list[key]
            if(! fns) {return false
            }
            if(! fn) { fn && (fns.length =0)}else {
                for (var i = fns.length - 1; i >= 0; i--) {
                    var _fn = fns[i]
                    if (_fn == fn) {
                        fns.splice(i, 1)}}}}// Secondary encapsulation
        var Event = (function () {
            var list = {},
                listen,
                trigger,
                remove;
            listen = function (key, fn) {
                    if (!this.list[key]) {
                        this.list[key] = []
                    }
                    this.list[key].push(fn)
                },
                trigger = function () {

                    / / get the key
                    var key = Array.prototype.shift.call(arguments)
                    var fns = this.list[key]
                    / / determine
                    if(! fns || fns.length ==0) {
                        return
                    }
                    for (var i = 0, fn; fn = fns[i++];) {
                        // fn.apply(this, arguments)fn(... arguments) } }, remove =function (key, fn) {
                    var fns = this.list[key]
                    if(! fns) {return false
                    }
                    if(! fn) { fn && (fns.length =0)}else {
                        for (var i = fns.length - 1; i >= 0; i--) {
                            var _fn = fns[i]
                            if (_fn == fn) {
                                fns.splice(i, 1)}}}}return {

                listen,
                trigger,
                remove
            }
        })()

Copy the code

Improved strong coupling in asynchronous operations

The business scenario

Let’s say you’re developing a mall website with a header, nav navigation, message list, shopping cart, and other modules. The common prerequisite for rendering of these modules is that the user’s login information must be obtained using an AJ AX asynchronous request. This is normal, for example, for the user’s name and avatar to be displayed in the header module, and both fields come from the information returned by the user after login

login. succ( function(data){/ / login. Function (data){
header. setAvatar( data.avatar); // Set the header image
nav. setAvatar( data.avatar ); // Set the image of the navigation module
message. refresh(); // Refresh the message list
cart. refresh(); // Refresh the shopping cart list});Copy the code

Strong coupling

The header header is called setAvatar, and the shopping cart is called refresh. This coupling will make the application stiff. The Heade R module cannot change the name of the setAvata R method at will. Its own name cannot be changed to header1,header2. One day, we add a shipping address management module to the project, and add this line of code at the end:

login. succ( funct ion(data){
header . setAvatar( data . avatar); // Set the header image
nav. setAvatar( data.avatar ); // Set the image of the navigation module
message. refresh(); // Refresh the message list
cart. refresh(); // Refresh the shopping cart list
address. refresh();
});
Copy the code

The publish and subscribe pattern achieves low coupling

After being rewritten in the public-subscribe pattern, business modules interested in user information will subscribe to the successful login message event themselves. When the login is successful, the login module only needs to publish the successful login message, and the business side will start their respective business processing after receiving the message. The login module does not care about what the business side wants to do, and does not want to know their internal details

// You just publish
$.ajax('http://xx. com? Login'.function (data) { // Login succeeded
    login.trigger('loginSucc ', data); // Publish a successful login message
});
// I just listen - each module listens for a successful login message
var header = (function () { / / the header module
    login.listen(' loginSucc'.function (data) {
        header.setAvatar(data.avatar);
    });
    return {
        setAvatar: function (data) {
            console.log('Set the header image'); }}}) ()var nav = (function () { / / nav module
    login.listen(' LoginSucc'.function (data) {
        nav.setAvatar(data.avatar);
    });
    return {
        setAvatar: function (avatar) {
            Iconsole.log('Set the avatar of nav module'); }}}) ();Copy the code