Article series

Javascript design pattern singleton pattern

The adaptor pattern of javascript design patterns

The Decorator pattern of javascript design patterns

Proxy mode of javascript design pattern

Comparison of javascript adaptation, proxy, and decorator patterns

State mode of javascript design mode

The iterator pattern of javascript design patterns

Policy mode of javascript design pattern

The Observer pattern of javascript design patterns

Publish subscriber mode of javascript design pattern

preface

In the last post, we talked about the observer model. This post will talk about the publis-subscribe model. One might say: Aren’t these two the same thing? Indeed there is no essential difference on the core thought and operation mechanism of these two modes. But there are some differences, otherwise I will tell you what I want to say in this article

In this paper, the code

What is the published subscriber model

Based on a topic/event channel, the object that wants to receive notifications (called Subscriber) subscribs to the topic through a custom event, and the object that has an active event (called Publisher) is notified by publishing the topic event.

The published subscriber model in life

Still remember last time that xiao Ming, xiao Hong, xiao er to the building to buy a house?

Xiao Ming recently took a look at a real estate, to the sales office was told after the house has not opened, the specific opening time has not been set. In addition to Xiao Ming, together with Xiao Hong, two people, in order to the first time that the opening time of the building, they left their phone number to the salesman Wang Wu, Wang Wu also promised that the opening of the building will send a message to inform them. After a while, the opening time of the new building was fixed, Wang Wu hurriedly took out the roster, traversed the number above, group sent a text message to inform them. It was up to these people to decide whether they would walk, drive or not

This is the observer mode.

But if Xiao Ming et al did not go to the sales office to find 50, but to the real estate website to check, that has not opened the development of the development. After the opening, Wang wu also does not send mass text messages, but synchronizes the news to the official website, so the official website automatically notifies interested buyers of the building. This is the publish subscriber model.

Key concepts are in place

Posted by: Wang Wu

Subscribers: Xiao Ming, Xiao Hong, Xiao Er

Event Center: official website

Subscribe events: Xiao Ming, Xiao Hong, Xiao Er enter the official website to pay attention to the development of the property

Notice changes: the official website automatically notifies prospective buyers of the property

What’s the difference?

  • In the published subscriber mode, there is no direct dependency between the publisher and the subscriber, and it is handled through the event center.
  • Publish subscriber mode – all publish/subscribe to events must go through the event center, and all “private deals” are prohibited.

Hand-published subscriber mode

Like the official website, the event center should emit events, listen on events, destroy event listeners (off), destroy all listeners (offAll), and only emit once

class EventEmitter {
	constructor() {
		// handleEvents is a map that stores the mapping between events and callbacks
		this.handleEvents = {}
	}
	/** * Register an event listener, which takes the event type and callback function as arguments *@param {String} Type Event type *@param {Function} Callback callback function */
	on(type, callback) {
		// Check whether there is a listener queue for the event type
		if (!this.handleEvents[type]) {
			Uncaught TypeError: Cannot read property 'push' of undefined) Uncaught TypeError: Cannot read property 'push' of undefined
			this.handleEvents[type] = []
		}
		// Push the callback function to the listener queue of the event type
		this.handleEvents[type].push(callback)
	}
	/** * publish an event, which takes the event type and the listener as arguments *@param {String} Type Event type *@param  {... any} Args argument list, assign the arguments passed by emit to the callback function */
	emit(type, ... args) {
		// Check whether the event type has a listener queue
		if (this.handleEvents[type]) {
			// If so, the callbacks in the queue are called one by one
			this.handleEvents[type].forEach((callback) = >{ callback(... args) }) } }/** * remove the specified callback function from an event callback queue@param {String} Type Event type *@param {Function} Callback callback function */
	off(type, callback) {
		const callbacks = this.handleEvents[type]
		const index = callbacks.indexOf(callback)
		// If found, remove
		if(index ! = = -1) {
			callbacks.splice(index, 1)}// If the callback function for the event type is empty, the object will be deleted
		if (callbacks.length === 0) {
			delete this.handleEvents[type]
		}
	}
	/** * remove all callbacks for an event@param {String} Type Event type */
	offAll(type) {
		if (this.handleEvents[type]) {
			delete this.handleEvents[type]
		}
	}
	/** * Register a single listener for an event@param {String} Type Event type *@param {Function} Callback callback function */
	once(type, callback) {
		// Wrap the callback function so that it is automatically removed after execution
		const wrapper = (. args) = > {
			callback.apply(args)
			this.off(type, wrapper)
		}
		this.on(type, wrapper)
	}
}

Copy the code

test

// Create an event manager instance
const emitter = new EventEmitter()
// Register a Refresh event listener
emitter.on('refresh'.function () {
	console.log('Call the background to get the latest data')})// Publish the event refresh
emitter.emit('refresh')
// Emit can also pass parameters
emitter.on('refresh'.function (pageNo, pageSize) {
	console.log({pageNo:${pageNo},pageSize:${pageSize}} `)
})
emitter.emit('refresh'.'2'.'20') // Two messages are printed because two listeners of the Refresh event have been registered

// Test to remove event listener
const toBeRemovedListener = function () {
	console.log('I am a listener that can be removed.')
}
emitter.on('testRemove', toBeRemovedListener)
emitter.emit('testRemove')
emitter.off('testRemove', toBeRemovedListener)
emitter.emit('testRemove') The event listener has been removed and console.log will no longer be printed

// Test to remove all refresh event listening
emitter.offAll('refresh')
console.log(emitter) // At this point, you can see that Emitter. handleEvents has become empty, and emit refresh events without any reaction

emitter.once('onlyOne'.function () {
	console.info('It will only trigger once.')
})
emitter.emit('onlyOne')
emitter.emit('onlyOne') // No message will pop up
Copy the code

Publish/subscribe usage scenarios

Event listeners

// Subscribe to these functions, triggering publication when clicked, which in turn triggers these functions
$('#btn1').click(function () {
	alert(1The $()})'#btn1').click(function () {
	alert(2The $()})'#btn1').click(function () {
	alert(3)})Copy the code

promise

Promise is the classic observer pattern: store the functions in then, reject and resovle, reject, and execute them. Collect dependencies -> trigger notifications -> fetch dependencies. You can see how to execute a handwritten promise

jQuery.Callbacks

  // Custom event, custom callback
  var callbacks = $.Callbacks() // Note the case, C is uppercase
  callbacks.add(function (info) {
    console.info('fn1', info)
  })
  callbacks.add(function (info) {
    console.info('fn2', info)
  })
  callbacks.add(function (info) {
    console.info('fn2', info)
  })
  callbacks.fire('come')
  callbacks.fire('go')
Copy the code

Event in node

const EventEmitter = require('events').EventEmitter
const emitter1 = new EventEmitter()
emitter1.on('some'.(name) = > {
	// Listen for some events
	console.info('some event is occured 1 ' + name)
})
emitter1.on('some'.() = > {
	// Listen for some events
	console.info('some event is occured 2')})// Triggers the SOME event
// And pass the parameters
emitter1.emit('some'.'zhangsan')
Copy the code

conclusion

Observer mode:

  • The roles are clear, with no event scheduler acting as an intermediary, and the target objects Subject and Observer both implement the prescribed member methods.
  • The two parties are more closely connected, and the target object is highly proactive, collecting and maintaining observers by itself, and proactively notifies observers of updates when the status changes.

Publish subscriber mode:

  • In the publis-subscribe model, the publisher does not directly touch the subscribers, but the actual communication is done by a unified third party, who does not care about each other.
  • Loose coupling, high flexibility, commonly used as an event bus

As you can see, the published subscriber model is more advanced because it is looser and has no coupling, so is the published subscriber model used more in reality? Actually, it’s not. Because in practice, our module decoupling request does not require them to be completely decoupled. If there is a stable and necessary relationship between two modules, then the observer mode should be used.

Refer to the link

Core principles and application practices of JavaScript design pattern

Talk briefly about the publish subscribe and observer patterns from an interview question

conclusion

Your “like” is my biggest affirmation, if you think it is helpful, please leave your praise, thank you!!