Vue responsive principle (simple understanding)

Let's supply this picture first

0. What is responsive

Explanation on the official website (you can read it selectively)

When you pass an ordinary JavaScript object into the Vue instance as the data option, Vue will traverse all the properties of the object and use object Defineproperty converts all these properties into getters / setters. Object.defineProperty is a feature in ES5 that cannot shim, which is why Vue does not support IE8 and earlier browsers.

These getters / setters are invisible to the user, but internally they enable Vue to track dependencies and notify changes when properties are accessed and modified. It should be noted that different browsers format getters / setters differently when printing data objects on the console, so it is recommended to install Vue devtools to obtain a more user-friendly interface for inspection data.

Each component instance corresponds to a watcher instance, which will record the "contacted" data property as a dependency during component rendering. Then, when the setter of the dependency is triggered, it will notify the watcher to re render its associated components.

Note:

  1. shim can introduce new API s into the old environment, and only rely on the existing means in the environment.

1. The key to achieving responsiveness

  1. Object.defineProperty
  2. Subscriber design pattern

2. Object.defineProperty() method

Object. The defineproperty () method defines a new property directly on an object, or modifies an existing property of an object and returns the object.

grammar

	Object.defineProperty(obj, prop, descriptor)

parameter

  1. obj
    The object whose properties are to be defined.
  2. prop
    The name or Symbol of the attribute to define or modify.
  3. descriptor
    The property descriptor to define or modify. (object)

Return value

The object passed to the function.

The key lies in the set and get methods in the passed descriptor parameter

Let's combine chestnuts

First, we define an object to simulate data in vue

    var obj = {              
      message: 'ha-ha',
      name: 'perry'     
    };

Then loop through the keys inside and call the defineProperty method for each property in obj

    Object.keys(obj).forEach(key => {
      let value = obj[key]
      Object.defineProperty(obj, key, {
        set(newValue) { // Call the set method when changing the attributes in obj (key)
          console.log("set");
          value = newValue
        },
        get() {// Call the get method when getting the properties in obj (key)
          console.log("get");
          return value
        }
      })
    })

Do you have an idea? Yes, we can do a lot in the set and get functions

3. Publish subscribe mode

Publish subscribe mode defines a one to many relationship between objects, allowing multiple observer objects to listen to a topic object at the same time. When the topic object changes, all objects that depend on it will be notified. (understand this sentence well!!!)

See an example to help understand

You pay attention to a on the microblog, and many other people pay attention to a, so when a releases the news, the microblog will push the news for you. A is the publisher, you are the subscriber, and microblog is the dispatching center. You and a do not have direct information exchange, but are coordinated through microblog
(your attention (subscription), A's publishing dynamics (Publishing)).

Take a direct look at its simple model:

	// Publisher
    class Dep {
      constructor() {
        this.Subscription = [] // Used to record all subscribers
      }
      addSub(watcher) { // Join subscriber
        this.Subscription.push(watcher)
      }
      notify() { // Notify each subscriber of updates
        this.Subscription.forEach(item => {
          item.update();
        })
      }
    }
    
    // Subscribers, also known as observers
    class Watcher {
      constructor(name) {
        this.name = name;
      }
      update() {
        console.log(this.name + "happen update");
      }
    }

4. Combination of the two

  1. We call the publisher's notify in set, which is to notify all subscribers to update as long as the obj changes.
    // 1. Traverse all keys in obj
    Object.keys(obj).forEach(key => {
      let value = obj[key]
        // 2. Listen for changes through the defineProperty method
      Object.defineProperty(obj, key, {        
        set(newValue) {
          // When changing the properties in obj, here
          value = newValue        
          dep.notify(); // Then, the subscriber of the corresponding dep (need to make judgment) is notified in this place. Different DEPs need to send notifications for different value changes (key)
          console.log('monitor' + key + 'change' + ':' + value)
        },
        get() {    
          // This is where the properties in obj are obtained
          console.log('obtain' + key + 'Corresponding value')
          return value
        }
      })
    })
  1. Then we create a publisher object and add subscribers to it

A dep object in an instance can be understood as what we need to do when adding data in data
Instantiating a watcher object and calling dep.addSub is what we need to do when using data

    // Instance is a dep object that simulates a data added to a data
    const name = new Dep();

    const w1 = new Watcher('Zhang San'); // Zhang San used it
    name.addSub(w1) // Zhang San becomes a subscriber and is placed in the subscription array

    const w2 = new Watcher('Li Si'); //Li Si used it
    name.addSub(w2) // Li Si becomes a subscriber and is placed in the subscription array
  1. Then, if we change the obj attribute, we will notify all subscribers

    Are you clear?
    Not clear. Let's take a look at the complete code. There are only two classes and one key logic
    var obj = {              
      message: 'ha-ha',
      name: 'why'     
    };
    Object.keys(obj).forEach(key => {
      let value = obj[key]
      Object.defineProperty(obj, key, {        
        set(newValue) {
          value = newValue        
          name.notify(); // Then notify the corresponding dep subscriber of the change in this place
        },
        get() {    
          return value
        }
      })
    })
    // Publisher
    class Dep {
      constructor() {
        this.Subscription = [] // Used to record all subscribers
      }
      addSub(watcher) { // Join subscriber
        this.Subscription.push(watcher)
      }
      notify() { // Notify each subscriber of updates
        this.Subscription.forEach(item => {
          item.update();
        })
      }
    }
    // Subscribers, also known as observers
    class Watcher {
      constructor(name) {
        this.name = name;
      }
      update() {
        console.log(this.name + "happen update");
      }
    }
    
    // Instance a dep object
    const name= new Dep();

    const w1 = new Watcher('Zhang San');
    name.addSub(w1) // Zhang San becomes a subscriber and is placed in the subscription array

    const w2 = new Watcher('Li Si');
    name.addSub(w2) // Li Si becomes a subscriber and is placed in the subscription array

reference resources

  1. MDN
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
  2. vue official documents
    https://cn.vuejs.org/v2/guide/reactivity.html
  3. codeWhy teacher's notes

Keywords: Front-end Vue

Added by joshi_v on Wed, 29 Dec 2021 08:33:30 +0200