This article describes the implementation and use of the publish/subscribe mode in JavaScript. Share it for your reference, as follows:
1. Introduction to publish/subscribe mode
Publish/Subscribe Mode (i.e. Observer Mode): The main driving force behind designing this mode is to promote the formation of loose coupling. In this pattern, it is not that one object calls another object's method, but that a subscriber object subscribes to a specific activity of the publisher object and that the subscriber object is notified after the state of the publisher object changes. Subscribers are also called observers, while the object being observed is called publishers or topics. When an important event occurs, the publisher will notify (call) all subscribers and may often pass messages in the form of event objects.
Basic idea: Publisher objects need an array type attribute to store all subscribers. Subscription (i.e. registration) is to add a new subscriber to this array, and logout is to delete a subscriber from this array. Additionally, publishing messages is to loop through the subscriber list and notify them.
2. How to publish subscribers?
My general idea here is correct. However, during the interview, I also said, "In addition to publishers, we need to define a new class - subscriber. In subscribers, we need to define a method similar to getNews so that the method is called when the publisher publishes a message." Then, the interviewer said that this is too troublesome, what if the subscribers don’t have this method? Then, I don't understand very much...
So I thought of passing the parameters directly when posting the message: = msg;
Then the interviewer said that this is not more troublesome? In this case, what if the subscriber does not have the news attribute? It also has to judge whether the subscriber has the news attribute. If it does not, an undifined error will occur.
Then, I didn't know what to do... Then the interviewer was very nice and told me that "can use inheritance or pass in a function when registering."
After the interview, go home and check the relevant knowledge online. The points you have sorted out are as follows:
- Sending a message, that is, notification, means calling a method of the subscriber object. Therefore, when a user subscribes to information, the subscriber needs to provide one of its methods to the publisher's subscribe() - this should be what the interviewer said is to pass in a method when registering.
- Each publisher object needs to have the following members:
subscribers
: an array that stores subscribers;subscribe()
: Register/subscribe, add subscribers to the subscribers array;unsubscribe()
: Unsubscribe. Delete subscribers from the subscribers array;publish()
: Loop through each element in the subscribers array and call the method provided when they are registered;
All three methods require a type parameter. This is because publishers may trigger multiple events (such as publishing a magazine and a newspaper at the same time), and subscribers may choose to subscribe to only one of them and the other does not.
3. Code implementation
Referring to the book "JavaScript Pattern", the code using literals is as follows:
// Since these members are common to any publisher object, it makes sense to implement them as part of a separate object. That way we can copy it into any object and turn any given object into a publisher.// Implement a general publisher as follows, defining the publisher object...let publisher = { subscribers: { any: [] }, subscribe: function (fn, type = `any`) { if (typeof [type] === `undefined`) { [type] = []; } [type].push(fn); }, unSubscribe: function (fn, type = `any`) { let newSubscribers = []; [type].forEach((item, i) => { if (item !== fn) { (fn); } }); [type] = newSubscribers; }, publish: function (args, type = `any`) { [type].forEach((item, i) => { item(args); }); } }; // Define a function makePublisher() which accepts an object as a parameter and converts it into a publisher by copying the above-mentioned general publisher method into the objectfunction makePublisher(obj) { for (let i in publisher) { if ((i) && typeof publisher[i] === `function`) { obj[i] = publisher[i]; } } = { any: [] }; } // Implement paper objectvar paper = { daily: function () { (`big news today!`); }, monthly: function () { (`interesting analysis`, `monthly`); } }; // Construct paper into a publishermakePublisher(paper); // Look at the subscription object joe, which has two methods:var joe = { drinkCoffee: function (paper) { (`Just read ` + paper); }, sundayPreNap: function (monthly) { (`About to fall asleep reading this ` + monthly); } }; // Paper registration joe (that is, joe subscribes to paper)(); (, `monthly`); // i.e. joe provides a callable method for the default "any" event, while another callable method is used when an event of type "monthly" occurs. Now let's trigger some events:(); // Just read big news today (); // Just read big news today (); // About to fall asleep reading this interesting analysis (); // About to fall asleep reading this interesting analysis (); // About to fall asleep reading this interesting analysis
I tried to write it in ES6's class grammar (PS: This was written by the reprinter himself, and the original author implemented it again with the function himself):
// Since these members are common to any publisher object, it makes sense to implement them as part of a separate object. That way we can copy it into any object and turn any given object into a publisher.// Implement a general publisher as follows, defining the publisher object...class Publisher { constructor(){ = { any: [] } } subscribe(fn, type=`any`){ if(typeof [type] === `undefined`){ [type] = []; } [type].push(fn); } unSubscribe(fn, type=`any`){ let newArr = []; [type].forEach((item, i) => { if(item !== fn){ (fn); } }); [type] = newArr; } publish(args, type=`any`){ [type].forEach((item, i) => { item(args); }); } // Define a function makePublisher() which accepts an object as a parameter and converts it into a publisher by copying the above-mentioned general publisher method into the object static makePublisher(obj){ = new Publisher(); } } // Implement person objectvar person = { sayHi: function(name){ (name); }, sayAge: function(num){ (num, `age`); } } // Construct person as a publisher(person); // Look at the subscription object myLover, which has two methods:var myLover = { name: ``, hello: function(name){ = name; (`Hi, i am ` + name + ` ! Nice to meet you!`); }, timeOfLife: function(num){ (`Hello! My name is ` + + ` ! I am ` + num + ` years old!`); } } // person register myLover (i.e. myLover subscribes to person)(); (, `age`); // That is, myLover provides a callable method for the default "any" event, and another callable method is used when an event of type "age" occurs. Now let's trigger some events:(`Jimmy`); // Hi, i am Jimmy ! Nice to meet you! (24); // Hello! My name is Jimmy ! I am 24 years old! (`Tom`); // Hi, i am Tom ! Nice to meet you! (6); // Hello! My name is Tom ! I am 6 years old! (18); // Hello! My name is Tom ! I am 18 years old!
For more information about JavaScript, you can also view the topic of this site: "JavaScript object-oriented tutorial》、《Summary of JavaScript Errors and Debugging Skills》、《Summary of JavaScript data structure and algorithm techniques》、《JavaScript traversal algorithm and skills summary"and"Summary of JavaScript mathematical operations usage》
I hope this article will be helpful to everyone's JavaScript programming.