There are several reasons why Vue3 is faster than Vue2:

  • Proxy implements responsiveness
  • PatchFlag
  • hoistStatic
  • CacheHandler
  • Tree-shaking

Due to the limited space, next to separate, this article will first talk about Proxy implementation reactive.

Object. DefineProperty faults

Let’s review the shortcomings of Object. DefineProperty for Vue2. X

  • Deep listening requires one-time recursion. Both the initialization and Set phases require deep listening
  • Unable to listen for new and deleted properties. To implement listening, use vue. set to add attributes and vue. delete to delete attributes
  • Unable to native listen array, requires special handling

Basic Use of Proxy

/** * Create responsive data *@param {Object|Array} data
 * @returns* /
function createProxyData (data) {
  return new Proxy(data, {
    get (target, key, receiver) {
      console.log('triggers get key=${key}`)
      const result = Reflect.get(target, key, receiver)
      console.log(` get results:${result}`)
      return result
    },
    set (target, key, value, receiver) {
      // Return Boolean
      console.log('triggers set key=${key},value=${value}`)
      const result = Reflect.set(target, key, value, receiver)
      console.log(` set results:${result}`)
      // Return the result true on success, false on failure
      return result
    },
    deleteProperty (target, key) {
      console.log('triggers deleteProperty key=${key}`)
      const result = Reflect.deleteProperty(target, key)
      console.log(` deleteProperty results:${result}`)
      return result
    }
  })
}
Copy the code

Let’s take a look at the output with an example

Object response

Create the responsivity of the object

const proxyData = createProxyData({ name: 'too cold'.phone: '* * * 186 * 8080' })
Copy the code
Get object properties
const proxyData = createProxyData({ name: 'too cold'.phone: '* * * 186 * 8080' })
console.log(proxyData.name) // Get the name value
Copy the code

The output

Trigger get key=name GET result: Too cool too coolCopy the code
Setting Object Properties
const proxyData = createProxyData({ name: 'too cold'.phone: '* * * 186 * 8080' })
proxyData.age = 20 / / triggers the set
Copy the code

Output result:

Set key=age,value=20 set result: trueCopy the code
Deleting object Properties
const proxyData = createProxyData({ name: 'too cold'.phone: '* * * 186 * 8080' })
delete proxyData.phone
Copy the code

Output result:

Trigger deleteProperty key=phone deleteProperty result: trueCopy the code

Object responsivity is very simple and can be implemented with simple code. Let’s look at array responsivity

The response of an array

Responsivity to create an array

const proxyArray = createProxyData(['a'.'b'])
Copy the code
The new value
const proxyArray = createProxyData(['a'.'b'])
proxyArray.push('c')
Copy the code

Output result:

Function push() {[native code]} set key=2,value=c set key=2,value=c Set key=length,value=3 Set result: trueCopy the code

Isn’t it strange to see the output, just a push(‘c’) call that triggers two get, two set. Let’s analyze:

  • Trigger get key=push: callpushMethod fires.We need to ignore
  • Get key=length: Sets the value of an array, or gets the current valuelengthThe length of the
  • Set key=2,value=c: set key=2,value=c
  • Set key=length,value=3: Updates the array length
Optimization 1: Ignore the array prototype method
function createProxyData (data) {
  return new Proxy(data, {
    get (target, key, receiver) {
      /** add 1: start **/
      / / ignore push, pop,... Properties on the prototype, and only listen for their own properties
      if (Reflect.ownKeys(target).includes(key)) {
        / / to monitor
        console.log('triggers get key=${key}`)}/** add 1: end **/
      const result = Reflect.get(target, key, receiver)
      return result
    },
    set (target, key, value, receiver) {
      /** add 2: start**/
      // Data is not reprocessed
      const oldValue = target[key]
      if (oldValue === value) {
        return true
      }
      /** add 2: end **/
      console.log('triggers set key=${key},value=${value}`)
      const result = Reflect.set(target, key, value, receiver)
      console.log(` set results:${result}`)
      // Return the result true on success, false on failure
      return result
    },
    deleteProperty (target, key) {
      console.log('triggers deleteProperty key=${key}`)
      const result = Reflect.deleteProperty(target, key)
      console.log(` deleteProperty results:${result}`)
      return result
    }
  })
}

const proxyArray = createProxyData(['a'.'b'])
proxyArray.push('c')
Copy the code

Output result:

Get key=length Set key=2,value=c set Result: trueCopy the code

Proxy implements responsiveness

According to the online analysis results, it can be seen that it is easy to realize the object responsiveness through Proxy. To implement array responsiveness, note two points:

  • Ignore the push and pop,… Properties on the prototype, and only listen for their own properties
  • Data is not reprocessed

Based on the above content, the following uses Proxy to achieve a simple response

// Create reactive
function reactive (target = {}) {
  if (typeoftarget ! = ='object' || target == null) {
    // If it is not an object or array, return
    return target
  }

  // Proxy configuration
  const proxyHanlder = {
    get (target, key, receiver) {
      / / ignore push, pop,... Properties on the prototype, and only listen for their own properties
      if (Reflect.ownKeys(target).includes(key)) {
        console.log('get', key) / / to monitor
      }
      const result = Reflect.get(target, key, receiver)

      // Deep monitor
      return reactive(result)
    },
    set (target, key, val, receiver) {
      // Duplicate data is not processed
      if (val === target[key]) {
        return true
      }

      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
        console.log('Existing properties', key)
      } else {
        console.log('New Properties', key)
      }

      const result = Reflect.set(target, key, val, receiver)
      console.log('set', key, val)
      return result
    },
    deleteProperty (target, key) {
      const result = Reflect.deleteProperty(target, key)
      console.log('delete property', key)
      return result
    }
  }

  // Generate a new object
  const proxyData = new Proxy(target, proxyHanlder)
  return proxyData
}
Copy the code

Test it out:

const data = {
  name: 'TaiLiang'.age: 18.address: {
    province: 'Beijing'}}const proxyData = reactive(data)
console.log(proxyData)

Copy the code

Vue3 is one of the reasons why Vue2 blocks

The benefits of Proxy implementation responsiveness

  • Deep listening level only goes to the next level, not all the way to the end, good performance
  • You can listen for new and deleted properties
  • You can listen for native array changes

From the above three points, we can see that Proxy can avoid the disadvantages of Object.defineProperty, but Proxy also has the disadvantages of not being compatible with all browsers and not being able to polyfill

The resources

  • Vue3
  • Vue3.2 response type source code analysis, and Vue2. X response type difference