Writing in the front

I’m currently reading JavaScript Design Patterns and Development Practices, and I’m currently working on project refactoring. This series of articles is the study of actual combat record and summary.

concept

The publish-subscribe model is also called the observer model. It defines a one-to-many relationship between objects in which all dependent objects are notified when the state of one object changes.

For a real life example, let’s say you really like a blog, but you don’t know when it’s going to be updated, so you check it every day or even every few hours to see if it’s updated. If you use the publish-subscribe model, you follow the blog’s public account, and when it updates, you receive a push message immediately.

Based on this, it’s easy to think of DOM events, bidirectional binding, vuex. Indeed, DOM events, Event objects, Proxy objects, and so on are typical applications of the publish-subscribe model in the JavaScript language. They all offer the ability to subscribe and publish.

Application scenarios

In addition to the use of native existing implementations, “web site login” and “inter-module communication” mentioned in the book are excellent application scenarios for this pattern. These examples illustrate the features and advantages of this pattern, and the code is posted here.

When an Ajax login is successful and the page data needs to be updated, this is what we typically do.

login.succ(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

Clearly, it creates a coupling. For example, we have added a module of shipping address, which also relies on user information. The inevitable login module is forced to open and add a call. When there are many modules, written by different people, the login module is forced to open more and more times and becomes overwhelmed.

We can solve this problem completely with a publish-subscribe model.

login.succ(function (data) {
  login.trigger('loginSucc', data) // Publish 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) {
      console.log('Set the avatar of nav module'); }}}) ();var address = (function () { / / nav module
  login.listen('loginSucc'.function (obj) {
    address.refresh(obj);
  });
  return {
    refresh: function (avatar) {
      console.log('Refresh shipping address list'); }}}) ();Copy the code

practice

DOM events are already familiar to you, so let’s take a look at the cornerstone of the Vue3.0 responsive principle: ES6 Proxy objects.

VUE officials give an example of what responsiveness is:

let obj = {
  val1: 2.val2: 3
}
let sum = obj.val1 + obj.val2
console.log(sum) / / 5
/ / change the value
obj.val1 = 3
// Sum is constant
console.log(sum) / / 5
Copy the code

When we update the first value, sum is not changed. This…… Of course, because JavaScript is usually “non-responsive”.

Let’s use Proxy+ publish-subscribe to make it responsive.

  1. First, based on Proxy, encapsulate a method to listen for value changes
// Use Proxy to listen for object changes
function addObjectListener(data, callback) {
  return new Proxy(data, {
    set(target, prop, value) {
      data[prop] = value
      callback()
      return value
    }
  })
}
Copy the code
  1. Add a listener to obj
let obj = {
  val1: 2.val2: 3
}
let sum = obj.val1 + obj.val2
console.log(sum) / / 5
/ / change the value
obj.val1 = 3
// sum is the same
console.log(sum) / / 5
// Add listener (subscribe)
obj = addObjectListener(obj, () = > {
  sum = obj.val1 + obj.val2
})
/ / change the value
obj.val1 = 3
// You can see the result change
console.log(sum) / / 6

obj.val2 = 8
console.log(sum) / / 11

Copy the code

As you can see, after adding the listener, we change the value again, and sum changes accordingly.

Back to the design pattern, the addObjectListener is the process of instantiating the publisher and adding a subscription, and the set callback triggers the publish/notify action.