Hello

Recently, while reviewing some common design patterns, I decided to organize an easy to understand article to explain its core ideas in association with the responsive principle (2.x) of VUE.

Ok, let’s get started.

The basic concept

The publish-subscribe pattern is based on a topic event channel, and objects receiving notifications can subscribe to a topic through a custom event and receive notifications when a topic event is published.

Said to launch a subscription model, had to carry the observer pattern, both of them maintain and rely on the events of the relationship between the object and the relevant state change will perform corresponding updates, so people often confuse the two, but the differences are obvious, events in the publish-subscribe pattern unified handling by the dispatching center, It can execute different events based on different topics, achieving complete decoupling and more flexibility.

A simplest example of a publish subscribe pattern

let pubSub = {
  subscribers: {},
  subscribe(key, fn) {
    if (!this.subscribers[key]) this.subscribers[key] = [];
    this.subscribers[key].push(fn);
  },
  unSubscribe(key) {
    delete this.subscribers[key]; }, publish(key, ... args) {let listeners = this.subscribers[key];
    listeners.forEach(fn= >fn(... args));// Notify all subscribers}};Subscribe ('event', () => {console.log('first event'); }); pubSub.subscribe('event', () => { console.log('second event'); }); pubSub.publish('event'); // first event second event */
Copy the code

Subscribers can subscribe by adding subscribers’ events in event schedulers (Subscribers) and then executing them on publish. Now let’s see how VUE implements a responsive system step by step.

The realization of vUE responsive principle

👆 is a diagram downloaded from the VUE website to illustrate how VUE triggers notification of changes when data changes through collected dependencies. It still looks a bit abstract, but let’s break it down a bit by combing through the main steps from a source code perspective.

  1. So init phase, let’s just do a little bit of Object. DefineProperty (obj, prop, Descriptor), descriptor has some properties, Get and set can customize Setters and Getters of attributes to make common objects observable. In this stage, all attributes of data in VUE will be reactive.
// vue/src/core/observer/index.js
const dep = new Dep()  // Instantiating the dependency manager ---- is described below
function defineReactive (obj,key,val) { // Convert objects to observables
  if (arguments.length === 2) {
    val = obj[key]
  }
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true.get: function reactiveGetter () {
      dep.depend() // Each data property has a DEP object, which is used to collect dependencies
      return value
    },
    set: function reactiveSetter (newVal) {
      if(val === newVal){
         return;
      }
      val = newVal;
      dep.notify() // Notifications depend on updates}})}// vue/src/core/observer/dep.js
class Dep { // The subscriber Dep holds the Watcher observer object, also known as the dependency manager
      statictarget: ? Watcher; subs:Array<Watcher>;
      depend () {
        if (Dep.target) {
          Dep.target.addDep(this) // Add a Watcher object
        }
      }
      addSub (sub) {
        this.subs.push(sub)
      }
      notify () {
        const subs = this.subs.slice()
        for (let i = 0, l = subs.length; i < l; i++) {
          subs[i].update() // Notify all Watcher objects to update the view}}}Copy the code
  1. In the mount phase, we put Watcher here because at this stage, an object of the Watcher class is created. Watcher is the observer that is responsible for subscribing to the Dep. There is one Watcher instance for each component instance.
/ / the vue/SRC/core/observer/watcher. Js (the following code fragment to simplify)
export default class Watcher {
  constructor (vm,expOrFn,cb) {
    this.vm = vm;
    this.cb = cb;
    this.getter = parsePath(expOrFn) // This function calls the component's render function to update the virtual DOM
    this.value = this.get()
  }
  get () {
    Dep.target = this // Assigns the current Watcher to dep.target
    const vm = this.vm
    let value = this.getter.call(vm, vm) // Call the update function of the component
    Dep.target = undefined
    return value
  }
  addDep (dep) {
    dep.addSub(this) // Register the Watcher object in the Dep of this property -- dependency collection
  }
  update () { // Perform updates when changes are received
    const oldValue = this.value
    this.value = this.get()
    this.cb.call(this.vm, this.value, oldValue)
  }
}
Copy the code
  1. In the update phase, the notify function of Dep will be called when the property in data changes, and then all Watcher will be notified to call the update function to render the component, that is, to distribute the update phase.

Observe: Observe Observe: Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Watcher is the bridge between components and data, and Dep acts as a dispatching center for collecting dependencies and managing notification updates.

(Tips: I think understanding these concepts is very important to understand the responsive principle, and reading the source code on this basis is much better.)

conclusion

This article introduces the principle and simple implementation of publish and subscribe mode, and according to the process of sorting out a brief introduction to the vUE responsive principle of the core idea, the article is not long, I hope to help you.

Time is short, the article will certainly have some not rigorous place, welcome everyone to correct and discuss.

Finally, thanks for reading!