regularjs/regular

如果使用 Date object 进行数据绑定就基本一定会有 Circular dependency reach

Closed this issue · 10 comments

如题。貌似是因为 Watcher check 的时候一直都是 dirty 的,是因为 Date object 本身是一直按毫秒级别在改变的吗?具体原因不太清楚,目前的 work around 是以毫秒为 key 来 cache 这个 Date object,并且每次先查cached,这样就能避免circular dependency。

Example:
https://codepen.io/anon/pen/wrgyqz

(打开 Devtool 看错误提示)

脏检查默认是简单判断 === , 前后的值每次都是new 出来的 一定是false ,所以造成了这个问题

@leeluolee 所以实际上应该是 new 的问题而不是 Date 的锅……所以是不是可以引申到所有用 new 的 Object 的数据绑定都会有 circular dependency reach 的可能,因为每次 new 肯定 === 是不同的

应该是你用到计算字段的问题,计算字段的计算函数在每次脏检查时都会执行
建议:

this.data.date = null;
// 当需要更新时
this.data.date = new Date(this.data.time)

我在想Date的话是不是可以特殊支持下

如果两个Date对象的timestamp一样的话,就认为是相等的,因为由相同的timestamp生成的Date对象,尽管引用不同,但基本上不会对视图产生影响

https://github.com/substack/node-deep-equal/blob/master/index.js#L11-L12
类似这边对Date的处理

如果想要更通用的话,可以在computed上提供一个类似diff的字段,由用户自行去处理这一类情况

{
    computed: {
        prop: {
            get() { return new Date( this.data.time ) },
            diff( current, last ) {
                return current && last && current.getTime() === current.getTime()
            }
        }
    }
}

或者配置一个全局的diff函数

Regular.config( {
    diff( current, last ) {
        if ( current instanceof Error && last instanceof Error && current.message === last.message ) {
            return true
        }
    }
} )

基本思路就是用户自定义的diff函数内置diff开始之前调用,如果返回true,则不再进行内置的diff,否则,继续使用内置的diff方案

不过这个例子的确只要$watch( 'time', ... ),然后给toDate重新赋值就可以了,不要使用computed

@fengzilong work around 当然是有的……但显得有点 imperative 和 hacky ,不够优雅,感觉那个 diff 是个不错的想法

@AndyRightNow 如果现有方案可以很简单地处理的话,我还是建议用现有方案,比如刚说的$watch的方式,这也不算hacky了,不过文档方面的确需要补充说明一下这点

如果你描述的场景现有api满足不了的话,到时再考虑加入新的feature?🤔

@AndyRightNow 这里对所有new出来的对象做基于引用外的比较可能不太现实,比如你要比较两个Promise实例是否相等,是不是还需要考虑Promise的status,resolve的值,reject的error等等,而且比较的过程还会变成异步的(then),加上还有用户自定义的一些class,对于大多数对象来说,基于引用比较设计上应该没什么问题,这里的问题应该是针对几类特殊的js内置对象,比如Date,是否有必要根据getTime进行比较,目前来说,例子中出现的computed这个现象应该是符合预期的

@fengzilong 正解, 其实这也是virtual dom的优势所在, 它只care 最终的html输出(view)变化, 而不在乎是那些数据改动导致的界面变化。 但是常规的mvvm通常对数据敏感, 做=== 判断是最安全的做法

@leeluolee 嗯,学到了,之前没仔细比较过两者,用virtual dom的话,数据层的一些细节的确就不需要考虑了