Vueconf (2018Hangzhou) Conference has just passed, vUE author You Dda showed us the progress of VUe3.0 and introduced some changes of VUe3.0, among which I am most looking forward to rewriting the data listening mechanism.

Review the bidirectional data binding of Ve2. X

When we talk about vUE’s two-way data binding, the first thing that comes to mind is object.defineProperty in ES5. Using get and set of overridden properties, we can accomplish data hijacking listening, and use observer mode to notify the subscriber to update the status when the data changes. We have written a simple code for the Observer section as follows:


function Observer (data) {
  this.data = data
  this.walk(data)
}
Observer.prototype = {
  walk: function (data) {
    let me = this
    Object.keys(data).forEach(function (key) {
      me.convert(key, data[key])
    })
  },
  
  convert: function (key, val) {
    this.defineReactive(this.data, key, val)
  },

  defineReactive: function (data, key, val) {
    let dep = new Dep()
    let childObj = observe()

    Object.defineProperty(data, key, {
      enumerable: true.configurable: false.get: function () {
        if (Dep.target) {
            dep.depend()  // Add subscribers
        }
        return val
      },
      set: function (newVal) {
        if (newVal === val)  return

        val = newVal
        childObj = observe(newVal)
        dep.notify()  // Notification subscriber}}}})function observe (value, vm) {
  if(! value ||typeofvalue ! = ='object') {
      return
  }

  return new Observer(value)
}

Copy the code

In the above code we define an Observer constructor, the Observer. With Object.defineProperty we listen for all attributes (including subattributes) of the passed Object and add a subscription to the subscriber in the GET method. Whenever a property changes, the subscriber is notified.

The Dep subscriber, Compile directive, and Watcher subscriber code are no longer analyzed. The overall structure of MVVM can be seen in the figure below

Introduction to Proxy

Proxy is a new constructor in ES6. It can be understood as a layer of “interception” in front of the target object. All external access to the object must pass this layer of interception, so it provides a mechanism for filtering and rewriting external access. Proxy means to act as a Proxy for certain operations.

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`proxy get ${key}`)
    return Reflect.get(target, key, receiver)
  },
  set: function (target, key, value, receiver) {
    console.log(`proxy set ${key}`)
    return Reflect.set(target, key, value, receiver)
  }
})
Copy the code

The code above sets up a layer of interception on an empty object. We can pass in the second parameter of the Proxy a handler object in which the interception behavior can be defined. We use Reflect in both get and set. Reflect objects, like Proxy objects, are a new API provided by ES6 for manipulating objects. The Reflect method corresponds to the Proxy method, such as the Proxy method intercepting the target attribute assignment behavior. It uses the reflect.set method to assign values to the properties of the object, ensuring that the original behavior is complete, and then deploys additional functionality. According to the above code we write a test code:

obj.text = 'hello world! ' 
// proxy set text
var _text = obj.text
// proxy get text
Copy the code

Proxy overwrite observer

Using some of the features of Proxy above, we modify the code as follows:

function observe (value, vm) {
  if(! value ||typeofvalue ! = ='object') {
    return
  }

  let dep = new Dep()
  return new Proxy(value, {
    get: function (target, key, receiver) {
      if (Dep.target) {
        dep.depend()
      }
      return Reflect.get(target, key, receiver)
    },
    set: function (target, key, value, receiver) {
      dep.notify()
      return Reflect.set(target, key, value, receiver)
    }
  })
}
Copy the code

We replace the passed object directly with a Proxy object, leaving the add subscriber and notification subscriber logic in the get and SET of the input parameter Handler unchanged. There is no extra judgment in the whole process. Since Vue3.0 has not been released yet, there is no actual source code to refer to, so the above is just a simple version of personal implementation (complete code). Apply the entire MVVM to HTML, and here’s what it looks like when it runs:

Benefits of rewriting the data listening mechanism

  1. To give upObject.defineProperty, based on Proxy observer mechanism to meet full language coverage and better performance. With other optimization changes, Vue3.0 can double the speed/halve the memory usage;
  2. ObserverModules will be available as a single library.

Possible problems

Unfortunately, the ES6 Proxy cannot be translated into ES5, so it will not be supported by IE. For this issue, Vue3.0 will give a compatibility solution for IE11, which still uses object.defineProperty under IE11.

The resources

ECMAScript 6 primer (nguyen piece) : es6.ruanyifeng.com/#docs/proxy vue 3.0 update plan: faster, smaller, let developers easier: www.oschina.net/news/101906… Why Proxy can optimize vue’s data listening mechanism: juejin.cn/post/684490…