Everyone is familiar with Watch, and the following notation has been used in the project:

watch: {
  someProp () {
    // do// watch: {someProp: {deep:true.handler () {
      // do something
    }
  }
}
Copy the code

This tells Vue that I need to listen for the someProp property to change, so vue internally creates a Watcher object for us. (Limited by space, we will not talk about the specific implementation of Watcher, interested can directly read the source code watcher)

In Vue, however, Watcher’s functionality is not so simple. Here’s the code:

<template>
  <div>
    <p>a: {{ a }}</p>
    <p>b: {{ b }}</p>
    <button @click="increment">+</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
    	a: 1
    }
  },
  computed: {
    b () {
    	return this.a * 2
    }
  },
  watch: {
    a () {
        console.log('a is changed')
    }
  },
  methods: {
    increment () {
    	this.a += 1
    }
  },
  created () {
    console.log(this._watchers)
  }
}
</script>
Copy the code

The online demo

The code above is very simple. We now focus on this._watchers printed in the Created hook as follows:

Expand the three watcher and observe each expression, from top to bottom, respectively:

  • B () {Return this. A * 2; ↵}
  • “a”
  • Function () {Address VM._update(vm._render(), hydrating); ↵}

The three watchers above represent three different types of watcher, which can be divided into three types according to their functions:

  • Watcher defined in Watch to listen for property changes (second)
  • Watcher for computed attributes (first)
  • Watcher for page updates (third)

normal-watcher

The ones we define in Watch are of this type, that is, whenever the listening property changes, the defined callback is triggered

computed-watcher

For each computed property, a corresponding Watcher object is eventually generated, but this kind of Watcher has a characteristic that we can take for example B above:

Property B depends on A, and when A changes, B does not recalculate immediately. It only evaluates later when b needs to be read elsewhere, which is lazy

render-watcher

Each component has a render-watcher, function () {Address vm._update(vm._render(), hydrating); This render-Watcher is called to update the component’s view when properties in data/computed change

Three watcher execution sequences

In addition to the functional differences, the three watcher also have a fixed order of execution, respectively:

computed-render -> normal-watcher -> render-watcher

This is done for a reason, so that as much as possible, computed properties are up to date when the component view is updated, and if render-watcher comes before compute-render, computed values will be old when the page is updated

summary

This article is not a source code analysis article, but it is a way to talk about how things that seem unrelated (computed/watch/ page updates) are closely related to each other. I hope it will inspire people to explore VUE more deeply