vuejs如何知道缓存的计算属性的依赖性?

Ami*_*ein 24 javascript vue.js vuejs2

我有这个Vue.js代码:

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

正如您所看到的,计算属性将被缓存,并且仅依赖于它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']
       }
  }
})
Run Code Online (Sandbox Code Playgroud)

额外奖励:我将很感激我链接到VueJS代码中的相关功能:https://github.com/vuejs/vue

Cod*_*Cat 16

它是Vue.js的反应系统,而不是缓存系统.

组件中的数据将转换为getter和setter.当您通过getter访问值时,getter会将其添加到依赖项中,当您通过setter修改该值时,setter将通知依赖于该值的每个人.

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

  • 如果是这个机制的话。这将会是越野车。在第二个例子中。如果我将“flag”值更改为“1”,我将在(flag==2)时获得缓存答案,而不是新答案。 (2认同)
  • 是的,这是一个有趣的问题。因为“flag”不是响应式的,所以“myCompulated”不会意识到“flag”的变化。这是演示:http://codepen.io/CodinCat/pen/rjOjjQ `flag` 将在 1 秒后更新,但计算属性不会对标志做出反应 (2认同)
  • `myCompulated` 只会在 10 秒后更新,因为您触摸了 `myOtherValue`。如果将间隔更改为“this.myValue += 1”,则“myCompulated”将永远不会更新,因为“myValue”不是“myCompulated”的依赖项 (2认同)
  • 所以正确的方法是将`flag`添加到该组件的数据中,然后将其转换为反应属性,并成为`myComputed`的依赖项,那么一切都应该完美. (2认同)
  • 这是另一个工作示例:http://codepen.io/CodinCat/pen/vgNgQy,以防您想要在组件外部使用变量。它必须是一个对象,当您将该对象提供给“data”时,它将转换为响应式属性,因此“myCompulated”可以正确地将其收集为依赖项 (2认同)

Mic*_*oka 10

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

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

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

通过修改此小提琴中的两个反应属性(通过简单地键入其相应的输入框)来观察此行为.有几点需要注意:

  • called计算出的属性是基于文档加载一次(它引发的,因为它在模板渲染).
  • 因为它path被设置为1将被映射为依赖关系的被动属性val1.因此,它将是唯一一个能够called在其变化时触发重新评估的人.即使它明显存在于函数中,它的值val2也可以改变但不会产生相同的效果called.
  • 当您单击"更改路径"按钮时,path将切换12.
  • 在路径切换之后,请注意,更改val1called仅影响一次.因为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
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

和相应的模板

<div id="app">
  <input v-model="val1"/> {{val1}}
  <br>
  <input v-model="val2"/> {{val2}}
  <br>
  <button @click="changePath">change path</button>
  <br>
  {{ called }}
</div>
Run Code Online (Sandbox Code Playgroud)

  • 我觉得这应该是公认的答案。我很感谢CodinCat分享到原始代码的链接,但我希望有人能给出其工作方式的要点。 (2认同)
  • @Yiping本质上,如果您希望计算函数注册特定的依赖项,则需要确保每次调用计算函数时都可以访问它们。作为一个简单的技巧,您可以将它们列在函数的开头。`this.val1; 顶部的 this.val2` 将对它们中的任何一个进行更改,重新触发对计算函数的调用。 (2认同)