vuejs 是如何知道 computed 属性 缓存的依赖关系的?

How vuejs knows the depenedencies of computed property for caching?

我有这个 Vue.js 代码:

new Vue({
  data:{
         myValue:'x',
         myOtherValue:'y'
  },
  computed: {
       myComputed: myFunction(){
          return this['my' + 'Value']
       }
  }
})

如您所见,计算出的 属性 将被缓存并且仅依赖于 data.myValue。我的问题是 Vue.js 缓存系统如何仅在 myValue 更改时再次知道 运行 计算函数?

如果我更改 myOtherValue 变量,myComputed 函数将使用缓存,并且不会 运行 再次调用它。

我想过几种可能的方法。但是 Vuejs 是怎么做到的呢? 我已阅读这篇文章:https://vuejs.org/v2/guide/computed.html,但没有找到答案。

这段代码中发生了什么,它将依赖什么?

const flag=2
new Vue({
  data:{
         myValue:'x',
         myOtherValue:'y'
  },
  computed: {
       myComputed: myFunction(){
          if (flag==1){
              return this['my' + 'Value']
          }
          else
              return this['my' + 'Other' + 'Value']
       }
  }
})

奖励: 我会感谢我 link VueJS 代码中的相关功能:https://github.com/vuejs/vue

这是Vue.js的反应系统,不是缓存系统。

组件中的数据将被转换为getters和setters。当您通过 getter 访问一个值时,getter 会将其添加到依赖项中,而当您通过 setter 修改该值时,setter 会通知所有人取决于价值。

这是源代码,所有的魔法都发生在这个函数中:https://github.com/vuejs/vue/blob/dev/src/core/observer/index.js#L131

从文档中可以看出: 计算的属性被缓存,并且仅在反应性依赖项更改时重新计算。 然而下面的 fiddle 显示了一些不同的东西。

  1. https://jsfiddle.net/z11fe07p/267/

从 fiddle 如果您将标志设置为 2,如果您更改 myOtherValue,计算的 属性 将被重新计算并执行,但是如果标志设置为 1。我认为它会跟踪您的 if 条件。

在文档中通常可以找到相关源代码的链接。 这是计算属性的代码:

我将只解决具体问题 vue.js 如何知道哪些依赖项影响哪些计算 属性?

简单的答案是,每次 vue 评估一个计算 属性 时,它都会创建一个映射,其中包含在该调用范围内访问的所有响应式属性。下次这些反应性属性中的任何一个发生变化时,它们将触发对计算 属性 的重新评估。

如果在计算的 属性 的最近评估期间,它的一个反应性依赖项从未达到(可能是因为它在 if/else 构造的非行进路径内),随后对该反应 属性 的更改不会触发对计算的 属性.

的重新评估

通过修改此 fiddle 中的两个反应属性来观察此行为(只需在相应的输入框中键入)。需要注意的几点:

  • called 计算 属性 在文档加载时计算一次(它被触发是因为它在模板中呈现)。
  • 因为 path 设置为 1,将映射为依赖项的反应式 属性 是 val1。因此,它将是唯一可以在 called 发生变化时触发重新评估的对象。 val2 的值也可以更改,但不会对 called 产生相同的影响,即使它明确存在于函数中。
  • 当您单击 "Change Path" 按钮时,path1 切换到 2
  • 在路径切换之后,请注意对 val1 的更改只会再次影响 called。由于 path 在上次重新评估之前已设置为 2,因此 val1 将无法访问,并且将不再映射为 called 的依赖项。此后对其值的后续更改不会触发 called 的重新计算。但是 val2 现在已被映射为 called 的依赖项,并且对它的更改会触发重新评估,就像之前对 val1 所做的一样。直到下一个路径从 2 切换回 1

这是代码。

let path=1
let count=0
const vm=new Vue({
  el:"#app",
  data:{
         val1:null,
         val2:null,
  },
  computed: {
       called: function(){

            if (path==1){
              this.val1
            }
            if (path==2){
                this.val2
            }
            return "I was just called "+ ++count +" times"
       }
  },
  methods: {
    changePath(){
        path = path==2 ? 1 : 2
    }
  }
})

和相应的模板

<div id="app">
  <input v-model="val1"/> {{val1}}
  <br>
  <input v-model="val2"/> {{val2}}
  <br>
  <button @click="changePath">change path</button>
  <br>
  {{ called }}
</div>