Giter Club home page Giter Club logo

Comments (7)

wangzongxu avatar wangzongxu commented on June 3, 2024

同楼上的问题;

还有个问题:
“之所以在深度观测之前不取值是因为属性原本的 getter 由用户定义,用户可能在 getter 中做任何意想不到的事情,这么做是出于避免引发不可预见行为的考虑。"

这句话中既然指出不进行深度观测的原因是因为用户可能在getter中做任何意想不到的事情,这个事情指的是什么;既然有这个顾虑,那为什么有setter函数的时候还会进行深度观测呢? 这个时候就不用顾忌用户的任意行为吗?

from vue-design.

liximomo avatar liximomo commented on June 3, 2024

因为用户可能在getter中做任何意想不到的事情

比如 getter 中发送请求, 此时这个请求应当在你主动访问的时候才会触发, 如果 vue 在定义响应式数据时替你触发了 getter, 这显然是不符合你预期的, 因为你并没有主动去触发.

既然有这个顾虑,那为什么有setter函数的时候还会进行深度观测呢?

这时候不是不用顾虑, 而是放弃顾虑. 我们来看看始终保证不触发 getter 会产生什么问题.

初始:

//  检测到 getter, 不去触发它, 所以 val 没有值
if (!getter && arguments.length === 2) {
    val = obj[key]
}

// 由于 val 没有值,  此处 observe(val) 没有任何作用,  所以初始时 val 不具备响应性
let childOb = !shallow && observe(val)

后续的赋值操作触发 setter

set: function reactiveSetter (newVal) {
      // ...省略
      
     if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }

      // newVal 被观测, 具备响应性, 与初始时不一致
      childOb = !shallow && observe(newVal)
      dep.notify()
    }

在属性自带 setter 的情况下, 如果初始时不去触发 getter 获取值进行深度观测, 就会造成再次赋值时, 新的值被观测. 此时会产生初次和后续数据响应的不一致. 当 getter 和 setter 同时存在时, 触发副作用和一致性有冲突, 当前的方案选择了保证一致性.

from vue-design.

wangzongxu avatar wangzongxu commented on June 3, 2024

@liximomo 非常感谢回答!

在属性自带 setter 的情况下, 如果初始时不去触发 getter 获取值进行深度观测, 就会造成再次赋值时, 新的值被观测. 此时会产生初次和后续数据响应的不一致. 当 getter 和 setter 同时存在时, 触发副作用和一致性有冲突, 当前的方案选择了保证一致性.

追问下哈:上边可能提问的不是很清楚

情况一共就下边四种应该是没问题的:

 if (getter && !setter) {
  //   初始化:不触发用户getter所以无副作用,不深度观测
  //   重新赋值:进行深度观测,破坏一致性
 }
 if (getter && setter) {
    //   初始化:触发用户getter有副作用,深度观测
    //   重新赋值:进行深度观测,保证一致性
 }
 if (!getter && setter) {
    //   初始化:无用户getter无副作用,深度观测
    //   重新赋值:进行深度观测,保证一致性
 }
 if (!getter && !setter) {
    //   初始化:无用户getter无副作用,深度观测
    //   重新赋值:进行深度观测,保证一致性
 }
  • 后边三种都为了保证了一致性,触发用户getter,导致副作用( vue 在定义响应式数据时替你触发了 getter);

  • 第一种情况为了保证无副作用,破坏了一致性(初始化时不深度观测,重新赋值时却深度观测);

为什么第一种情况很特殊呢?

from vue-design.

liximomo avatar liximomo commented on June 3, 2024

第一种仅存在 getter 的情况不存在你说的不一致, 我们仔细看下源码.

重新赋值时却时会对新的值进行深度观测, 这个逻辑是没错的:

set: function reactiveSetter (newVal) {
      // 略
      if (setter) {
        setter.call(obj, newVal)
      } else {
        // 没有 setter, 所以值被赋值给了 val,
        val = newVal
      }
      // val  被深度观测了
      childOb = !shallow && observe(newVal)
      dep.notify()
    }

但是我们看一下 get:

get: function reactiveGetter () {
     // 由于存在 getter,  所以 value 的值总是从 getter 中获得, 和 val 没有关系.
      const value = getter ? getter.call(obj) : val

     // 略
     return value
    }

看到了吗, 新值是会被深度观测, 但由于有自定义的 getter 存在, 所以 get 获取的值总是初始的值, 随变你 val 怎么变, 都和我无关.

还有你的最后两种情况由于 getter 不存在, 所以不存在触发副作用的担忧.

from vue-design.

wangzongxu avatar wangzongxu commented on June 3, 2024

@liximomo 感谢回答!!!

from vue-design.

caoyongqiang avatar caoyongqiang commented on June 3, 2024

虽然作者已关闭了这个issue,但是我觉得这块还是有点绕,再补充一段代码辅助说明下。

const data = {}
const value = {getterProp: {a: 1}}
Object.defineProperty(data, 'getterProp', {
  enumerable: true,
  configurable: true,
  get: () => {
    return value.getterProp;
  },
  set: (newValue) => {
    value.getterProp = newValue;
  },
})

const ins = new Vue({
  data,
  watch: {
    'getterProp.a': () => {
      console.log('触发watch绑定的依赖')
    }
  }
})
// 如果采用以前的方案,即不对是否有setter进行判断,如下
if (!getter && arguments.length === 2) {
  val = obj[key]
}
// 执行
ins.getterProp.a = 2;
// 此时是不会触发watch的。重新赋值后。
// 接下来给属性重新赋值
ins.getterProp = {
  a: 1,
}
// 然后改变属性的值
ins.getterProp.a = 2; // 此时又会触发watch。所以说响应数据的行为是不一致的
// 为了解决这个问题,采用了现在的方案,即对setter进行判断,如下
if ((!getter || setter) && arguments.length === 2) {
  val = obj[key]
}
// 执行
ins.getterProp.a = 2; // 此时会触发watch。重新赋值后。
// 接下来给属性重新赋值(注意,此时也会触发watch,因为属性a的值变了,可忽略这次触发,不是重点关注)
ins.getterProp = {
  a: 1,
}
// 然后改变属性的值
ins.getterProp.a = 2;
// 此时仍然会触发watch。响应数据的行为是一致的

from vue-design.

shengrongchun avatar shengrongchun commented on June 3, 2024

看来看去当既有getter也有setter的时候会有影响,那为什么不把
let childOb = !shallow && observe(val)放入
get: function reactiveGetter () { const value = getter ? getter.call(obj) : val; childOb = !shallow && observe(value);请有知道的帮忙解释下,谢谢了

from vue-design.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.