Analysis of JavaScript Design Patterns-publish-subscribe/Viewer mode

Source: Internet
Author: User

I've been writing CSS3 articles for some time.
I've never written design patterns.
To write about the famous observer pattern today.
Draw a picture first

Understanding of the Observer pattern

I think it's easier to say that the publish-subscribe model is more understandable.
(but there are some books that say they are two models ...). )
It's like we subscribed to the public number on the platform.
When it has a new post, it will be pushed to all of us who subscribe

We can see the advantages of this pattern in the example

    • We as subscribers do not have to see this public number every time there are no new articles published,
      Public number as a Publisher will notify us at the appropriate time
    • We are no longer strongly coupled with the public number. The public number doesn't care who subscribed to it,
      Whether you're a male or a female or a pet dog, it only needs to be regularly posted to all subscribers

Very simple truth, when the Chinese New Year, Mass blessing SMS must be more convenient than texting

The advantages of our observer pattern are mapped out by the above example

    • Can be widely used in asynchronous programming, it can replace our traditional callback function
      We do not need to focus on the internal state of the object during the asynchronous execution phase, we only care about the point in time of event completion
    • Instead of a hard-coded notification mechanism between objects, an object does not have to explicitly invoke the interface of another object, but loosely-coupled connections
      Although we do not know the details of each other, but do not affect mutual communication. More importantly, one of the object changes does not affect the other object

I might have seen these faces, but it's okay.
Below we will take a deep look at its advantages

Custom events

In fact, the observer pattern we've all used, is the event we're familiar with.
But the built-in events often don't meet our requirements.
So we need custom events

Now we want to implement this function
Defines an event object that has the following functions

    • Listen for events (subscribe to public numbers)
    • Trigger event (public number release)
    • Remove event (Order public number)

Of course we can't just subscribe to a public number, there may be many
So we're going to set different "keys" for different events.
So the structure of our store events should be like this.

//伪代码Event = {    name1: [回调函数1,回调函数2,...],    name2: [回调函数1,回调函数2,...], name3: [回调函数1,回调函数2,...],}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

The code is as follows

var Event = (function(){VarList = {}, listen, trigger, remove; Listen =function(KEY,FN) {Listener Event functionsif (!List[key]) {List[key] = [];If the event list does not yet have a key value namespace, create}List[key].push (FN);Pushes the callback function into the object's "key" corresponding to the "value" callback array}; Trigger =function(){Triggering event functionsvar key =Array.prototype.shift.call (arguments);The first parameter specifies a "key" MSG =List[key];if (!msg | | msg.length = = =0) {ReturnFalseReturns False if the callback array does not exist or is empty}Forvar i =0; i < msg.length; i++) {msg[i].apply (this, arguments);Loop callback array execute callback function}}; remove =function(Key, FN) {Removing event functionsvar msg =List[key];if (!msg) {ReturnFalseEvent does not exist directly returns false}if (!fn) {Deletelist[key]; //if there are no subsequent arguments, delete the entire callback array} else{for (var i = 0; i < msg.length; i++) {if (fn = = = Msg[i]) {Msg.splice (i, 1); //Delete the callback function in the specific callback array}}}; return {listen:listen, Trigger:trigger, Remove:remove}}) (); var fn = function ' a public number ', FN); Event.trigger ( ' a public number ',  ' 2016.11.26 '); Event.remove ( ' a public number ', FN);           

With this global event object, we can use it to communicate between two modules
and two modules do not interfere with each other

function(){    Event.listen(...);}module2 = function(){    Event.trigger(...);}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
The complete Observer object

There are still some problems with the event object we wrote above.

    • You can only "subscribe" and "Publish" first
    • Global objects generate naming conflicts

For the 1th, before we subscribe to a public number, it is also timed to push messages
Once we subscribe, we can also view historical push
So we should be implementing a pre-release re-subscription can still view historical messages

For the 2nd, if each of us uses the function we defined above
All events are placed in a list
It's been a long time. Naming conflicts will occur
The best way is to add the ability to create a namespace for objects
And now we're going to plump our event object
(Here I steal the code written by the great God, different people have different ways to implement the library)
Just a little bit more about this full version.

var Event = (function(){var global =This, Event, _default =' Default '; Event =function(){var _listen, _trigger, _remove, _slice =Array.prototype.slice, _shift =Array.prototype.shift, _unshift =Array.prototype.unshift, Namespacecache = {}, _create, find, each =function(ARY,FN) {VAR ret;Forvar i =0, L = ary.length; I < L; i++) {var n = ary[i]; ret = Fn.call (n,i,n); }return ret; }; _listen =function(Key,fn,cache) {if (!cache[key]) {Cache[key] = [];} cache[key].push (FN); }; _remove =function(KEY,CACHE,FN) {if (Cache[key]) {if (FN) {Forvar i = cache[key].length; I >=0; i--) {if (cache[key][i] = = = fn) {Cache[key].splice (I,1); } } }else{Cache[key] = [];}} }; _trigger =function(){var cache = _shift.call (arguments), key = _shift.call (arguments), args =arguments, _self =This, ret, stack = Cache[key];if (!stack | |!stack.length) {Return }Return each (Stack,function(){This.apply (_self,args); }); }; _create =function(namespace) {var namespace = namespace | | _default;var cache = {}, offlinestack = [],Offline event ret = {listen:function(Key,fn,last) {_listen (Key,fn,cache);if (offlinestack = = =NULL) {Return }if (last = = =' last ') {offlinestack.length && Offlinestack.pop () ();}else{each (Offlinestack,function(){This (); }); } Offlinestack =Null }, one:function(Key,fn,last) {_remove (Key,cache);This.listen (Key,fn,last); }, remove:function(KEY,FN) {_remove (KEY,CACHE,FN);}, Trigger:function(){VAR fn, args, _self =This _unshift.call (Arguments,cache); args =Arguments fn =function(){Return _trigger.apply (_self,args); };if (offlinestack) {Return Offlinestack.push (FN); }return FN (); } };Return namespace? (Namespacecache[namespace]? Namespacecache[namespace]: namespacecache[namespace] = ret): ret; };Return {create: _create, one:function(Key,fn,last) {var event =This.create (); Event.one (Key,fn,last); }, remove:function(KEY,FN) {var event =This.create (); Event.remove (KEY,FN); }, listen:function(Key,fn,last) {var event =This.create (); Event.listen (Key,fn,last); }, Trigger:function(){var event =This.create (); Event.trigger.apply (Thisarguments); } }; }();return Event;}) ();/********* first post-subscription *********/event.trigger (' Click ',1); Event.listen (' Click ',function(a) {Console.log (a);//1}); /********* uses the namespace *********/event.create (' Namespace1 '). Listen (' click ',function(a) { Console.log (a); //1}) Event.create ('namespace1 '). Trigger (' click ',1); Event.create (' Namespace3 '). Listen (' click ',function(a) {Console.log (a); //2}) Event.create ('namespace3 '). Trigger (' click ',2);          

Summarize

The observer pattern has two distinct advantages

    • Time decoupling
    • Decoupling between objects

It is widely used, but it has its drawbacks.
Creating this function also requires memory, which makes it difficult to track maintenance

Analysis of JavaScript Design Patterns-publish-subscribe/Viewer mode

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.