Explain the client message framework design principles in JavaScript _ basics

Source: Internet
Author: User
Tags emit unique id

Wow--it's a dangerous subject, isn't it? Our understanding of what is essential will, of course, change as we understand how to solve the problem. So I wouldn't lie--the nature of what I understood a year ago was unfortunate and incomplete, because I was sure that what I was about to write was nearly 6 months old. So this article is a glimpse of some of the key points I have used to successfully use the client message pattern in discovering JavaScript.

1. Understand the difference between the mediator and the Observer
most people like to apply "publisher/subscriber" (PUB/SUB) when describing any event/message mechanism--but I don't think the term is very well connected to abstraction. Of course, fundamentally, some things subscribe to events that are released by something else. But the way publishers and Subscribers are packaged together is likely to make a good model dim. So, where is the difference?


Observer

The Observer pattern includes an object that is observed by one or more observers. Typically, the object records all traces of the observer, usually using a list to store the callback method that the observer registers, which are subscribed by the observer to receive the notification. Note: (Oh, puns, how much I love them) (Translator Note: Observe observation, attention)

var observer = {
 listen:function () {
  console.log ("Yay for more clichéexamples ...");
var elem = document.getElementById ("cliche");
Elem.addeventlistener ("click", Observer.listen);

Some things to be aware of are:

    • We must obtain a direct reference to this object
    • This object must maintain some internal state, preserving the observer's callback traces
    • Sometimes the listener will not take advantage of any arguments returned by this object, theoretically, there may be 0-n* parameters (more depends on how interesting it will be later)

* n is actually not infinite, but for the sake of discussion it means the limit that we can never reach.


intermediaries

The mediator pattern introduces a "third party" between an object and an observer-effectively decoupling the two and encapsulating how they communicate with each other. An intermediary's API may be as simple as "publish", "subscribe", "unsubscribe", or a domain-wide implementation may be provided to hide these methods in some more meaningful semantics. Most of the server-side implementations I've used tend to be more domain rather than simpler, but there is no rule limit for a generic mediator! It's not uncommon to think that a generic intermediary is an information broker. In any case, the result is the same--a specific object and observer no longer know each other directly:

It ' s fun to be naive! var mediator = {_subs: {},//A real subscribe would in least check to make sure the//same callback instance wasn ' t
 Registered 2x.
 Sheesh, where did they find this guy?! Subscribe:function (topic, callback) {This._subs[topic] = This._subs[topic] | |
  [];
 This._subs[topic].push (callback); },//Lolwut? No ability to pass function context? :-) publish:function (topic, data) {var subs = This._subs[topic] | |
  [];
  Subs.foreach (function (CB) {CB (data);
 });
} var fathertime = function (med) {this.mediator = med;}; FatherTime.prototype.wakeyWakey = function () {this.mediator.publish ("Alarm.clock", {time: "06:00 AM", Cansnooze: "H
Eck-no-get-up-lazy-bum "});
 var Developer = function (mediator) {this.mediator = mediator;
This.mediator.subscribe ("Alarm.clock", This.pleasegodno);
}; Developer.prototype.pleaseGodNo = function (data) {alert ("ZOMG, it S" + Data.time +).
Please just make it stop. ") var fathertime = new Fathertime(mediator);
var developer = new Developer (mediator);
 Fathertime.wakeywakey ();

You might think that, in addition to a particularly pure intermediary implementation, a particular object no longer has the responsibility to keep the subscriber list, and that the "Fathertime" and "Developer" (Developer) instances never really know each other. They just shared a message--it's a very important contract, as we'll see in the future. "Very well, Jim." This is still a publisher/subscriber to me, so what's the point? Does it really make a difference if I choose a certain direction? "Oh, go on, dear readers, go on."

2. Know when to use intermediaries and observers

Using local observers and intermediaries, which are written in components, and intermediaries look like communication between remote components. Anyway. The principle of my treatment of this situation is--tl;dr (too long; Don ' t read) (too long, not readable). But anyway, it's best to cascade together anyway.

It's a hassle to say, just like a few months of meticulous experience compressed into a ditch with no more than 140 words. In reality the answer to this question is certainly not concise. So there's a long version of the explanation:

Does the observer need to refer to other projects besides the data map? For example, the Backbone.view view has various reasons to refer directly to its model. This is a very natural relationship, and the view is not only to render when the model changes, but also to invoke the event handling of the model. If the answer to the first question is yes, then the observer is meaningful.
If the relationship between the observer and the observer is simply dependent on the data, then I am willing to use the intermediary Pub/sub method. The communication between two backbone.view views or models is appropriate for the observer. For example, the message that controls the view of the navigation menu, which is required by the breadcrumbs (breadcrumb) (in response to the current level). A pendant does not need to refer to the Navigation view, it only needs the Navigation view to provide information. More crucially, navigation views may not be the only source of information, and other views may also be available. At this point, the intermediary pub/sub mode is the most ideal-and its own scalability is good.

It looks so good and comprehensive, but there is still a dew point: if I define a local event to the object, I want the observer to call directly, and can be indirectly accessed by the Subscriber, how to do? That's why I said to be chained together: you push or bridge the local event to the message group. Need some more code? It's possible--but it's better than the way you pass the observation on to all the observers, all the time tightly coupled. Then, we can continue the following two points well ...


3.) Selective "submit" local events to the bus

In the beginning I almost only used observer mode to trigger events in JavaScript. This is the pattern we've come across again and again, but the more popular client-side library behavior is fundamentally a mixed broker, providing us with APIs like they are observer patterns. When I first wrote Postal.js, I began to walk into the stage of "intermediary for all things." In the prototypes and constructors I've written, it's not uncommon for distribution and subscription calls to be distributed everywhere. When I benefit from the natural decoupling of this change, the base code begins to seem to be filled with the underlying part. Constructors have to take a channel everywhere, subscriptions are created as part of a new instance, and the prototype method publishes a value directly to the bus (even local subscribers cannot directly and must listen to the bus for information). Incorporating these obvious things about the bus into these parts of the app begins to smell like code. The "narrative" of the code always seems to be interrupted, such as "Oh, post this to all Subscribers," and so on! Wait a minute! Listening to this channel thing. OK, now go on. " My tests suddenly started to rely on the bus to do low-level unit tests. And it feels a little wrong.

The pendulum swung to the middle, and I realized that I should keep a "local API" and extend the data it could reach through an intermediary when needed. For example, my backbone view and model still send events to local observers using normal backbome.events behavior (that is, the model's events are observed by its corresponding view). When other parts of the app needed to know the changes in the model, I started to connect the local events to the bus bridge through these rows:

var Somemodel = Backbone.Model.extend ({
 initialize:function () {
  This.on ("Change:superimportantfield") function (model, value) {
   postal.publish ({
    channel: "Somechannel",
    topic: " Omg.super.important.field.changed ",
    data: {
    muyimportante:value,
    otherfoo:" Otherbar "
    }
   );
  } );
 }
});

It is important to realize that local events and messages must be considered separate contracts-at least conceptually-when it is possible to push events transparently to the message bus. In other words, you need to be able to modify the "internal/local" event without breaking the message contract. This is an important fact to remember in your mind-otherwise you are providing a new way for tight coupling, and you're going the other way!

So, of course, the above model can be tested without a message bus. And if I remove the logic that bridges between local events and buses, my views and models still work well. However, this is a seven-line example (albeit formatted). It takes almost 30 lines of code to bridge only four events.

Oh, how can you do both--local notification when it's right for the direct observer, and you can extend the event involved so that your object doesn't have to send a circle to all the objects--no code bloat is needed. How can the notification be less code and have more flavor?

4. Hide the template in your frame

This is not to say that the code in the above example-the syntax or concept of connecting an event to the bus-is wrong (assuming you accept the concept of local and remote/bridging events). However, this is a good example of the role of cultivating good habits on the basis of code. Sometimes we hear complaints like "too much code" (especially when LOC is the only judge of code quality). In this case, I agree. It's a terrible model.   Below is the pattern I used when bridging the backbone object's local event to Postal.js:
 

The logic to wire up publications and subscriptions//exists in our custom Msgbackboneview constructor var Someview = Msgbackboneview.extend ({className: "I-am-classy",//bridging local events triggered from this view publications: {//This is the common ' shorthand ' syntax//the ' key ' of the ' name ' of the event. The//value is ' Channel topic ' in postal. So this//means the Bridgetoofar event would get//published to Postal on the "Comm" Channel//using a topic of "" S.far.enough ".
 By default//The 1st argument passed to the event callback//would become the message payload. Bridgetoofar: "Comm Thats.far.enough",//However, the longhand approach works as this://The key is still the eve
 NT name that would be bridged. The value is ' an object ' provides a channel name,//a topic (which can be a string or a function returning//a S
 Tring), and a optional data function that the Returns//the object of that should is the message payload. BridgeBurned: {channel: "Comm", topic: "Match.lit", Data:function () {return {id:this.get ("id"), foo: ' Bar '}; },//This are how we subscribe to the bus and invoke//local methods to handle incoming messages subscriptions:
  {//The key is the ' the ' of the ' method ' to invoke.
  The value is the ' channel topic ' to subscribe.  So this would subscribe to the "Hotchannel" channel//with a topic binding of "start.burning.*", and any/
  Arriving gets routed to the "Burnitwithfire"//method on the view.  Burnitwithfire: "Hotchannel start.burning.*"}, burnitwithfire:function (data, envelope) {//do stuff with message
 Data and/or envelope}//other wire-up, etc.});


Obviously you can do this in several different ways--choosing a bus-style framework--which is much less irrelevant than the boilerplate approach, and is well known to backbone developers. When you control the implementation of both the event dispatcher and the message bus, the bridge is easier to connect. Here is an example of bridging the Monologue.js transmitter to Postal.js:

Using the ' Monopost ' Add-on for monologue/postal:
//Assuming we have a worker instance that has monologue
//M Ethods on its prototype chain, etc. The keys are event
//topic bindings to match local events to, and if a match
are//found, it gets published to th e channel specified in
the//value (using the same topic value)
worker.gopostal ({"
 match.stuff.like.#": "Thi Schannelyo ",
 " secret.sauce.* ":" Seeecretchannel ",
 " Another.*.topic ":" Yaymoarchannelschannel "
});

The use of templates in different ways is a pleasant good habit. Now I can independently test my local objects, bridge code, and even test the production & consumption expectations of both the message process and so on.

It is also important to note that if I need to access the generic postal API in the above scenario, nothing can prevent me from doing so. No loss of flexibility so it's a success.


5.) The message is the contract--to choose the way to implement wisely

There are two ways to pass data to subscribers--perhaps a more "official" label for them, and I'll describe them like this:

    • "0-n Parameters"
    • "Envelope" (or "single object Payload")

Take a look at these examples:

0-n args
this.trigger ("someguyblogged", "Jim", "Cowart", "JavaScript");
Envelope style
this.emit ("someguyblogged", {
 firstName: "Jim",
 lastName: "Cowart",
 Category: " JavaScript "
});
/*
 in a emitter like Monologue.js, the emit call above would actually publish a
 envelope that looked similar
   to this:
 {
  topic: "Someguyblogged",
  timeStamp: "2013-02-05t04:54:59.209z",
  data: {
   FirstName: "Jim",
   lastName: "Cowart",
   Category: "JavaScript"
  }
 }
* *

Over time, I've found that the envelope is a lot less troublesome (and code) than the 0-n parameter approach. The challenge of the "0-n parameter" approach is mainly for two reasons (as far as my experience is concerned): first, it is typically "when an event is triggered, do you remember which parameter to pass?" Don't you remember? Well, I think I'll look at the triggering source. " It's not really a good way to do it, is it? But it can interrupt the normal flow of code. You can use a debugging tool to detect parameter values under execution conditions and thus infer "tags" based on these values, but which is simpler--see a parameter value of "1.21", confuse its meaning, or detect an object and find {thousand MW: 1.21}. The second reason is that the accompanying event transmits optional data, as well as the pain when the method signature becomes longer.


"To tell you the truth, Jim, you're in a hitchhiking booth." "Maybe yes, but for a while I've been seeing the base of the code expanding and morphing, a simple primitive event containing one or two parameters that, in the meantime, contains optional parameters that begin to become deformed:

The beginning is such
This.trigger ("Someevent", "a string!",);
One day, it became a part of everything
This.trigger ("Someevent", "string", "{Sky: Blue"}, [1,2,3,4], true, 0);
But so on--the 4th and 5th parameters are optional, and therefore may also be transmitted by:
This.trigger ("Someevent", "string", "{"), [1,2,3,4], true, 0);
Oh, do you also check the 5th argument's true/False
? Hey, yo! Now it's the previous argument
... This.trigger ("Someevent", "string", +, True, 0);

If any of the data is optional, there will be no tests around it. But less code is needed to be more scalable, especially if you can interpret (thank these member names) so that you can test one object at a time by passing it to the Subscriber callback method. I still have to use it where I have to use the "0-n parameter", but if I decide, it will be the way to keep the envelope-my event sender and the message bus. (Indicating my bias, monologue and postal share the same envelope data structure, removing the monologue unused channel)

Thus, it is recognized that the structure used to transmit data to subscribers is part of the "contract". In this direction, you can use additional metadata to describe the event (no additional parameters need to be added)-This keeps the method signature (which is part of the contract) consistent with each event and subscriber. You can also easily make a version of an information structure (or add other envelope level information if necessary). If you follow this direction, make sure that you are using a consistent envelope structure.


6. The message "Topology" is more important than you think .

There is no silver bullet here. But you have to be thoughtful about how to name the topic and channel, and how to design the message payload structure. I tend to map my model in one of two ways: with a single data channel, the prefix of the subject takes the name of the model, followed by its unique ID, and then processed by its operation ({modelType.id.operation}), or by its own channel to the model, with the theme { Id.operation}. A constant habit is to automatically respond to this behavior when the model requests data. However, not all operations on the bus are requests. There may be simple events published to the app. Do you name the topic to describe the event (ideally)? Or have you fallen into such a trap by naming the topic to describe a subscriber's possible propensity behavior? For example, messages that contain "route.changed" or "Show.customer.ui" topics. One indicates the event, and the other indicates the command. Think carefully when you make these decisions. The command is not bad, but before you need a request/response or command, you will be amazed at the number of events that can be described.

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.