Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day92:既然 Vue 通过数据劫持可以精准探测数据在具体dom上的变化,为什么还需要虚拟 DOM diff 呢? #904

Open
Genzhen opened this issue Jul 7, 2020 · 8 comments
Labels
Vue teach_tag

Comments

@Genzhen
Copy link
Collaborator

Genzhen commented Jul 7, 2020

No description provided.

@Genzhen Genzhen changed the title 既然 Vue 通过数据劫持可以精准探测数据在具体dom上的变化,为什么还需要虚拟 DOM diff 呢? Day92:既然 Vue 通过数据劫持可以精准探测数据在具体dom上的变化,为什么还需要虚拟 DOM diff 呢? Jul 7, 2020
@Genzhen Genzhen added the Vue teach_tag label Jul 7, 2020
@Genzhen
Copy link
Collaborator Author

Genzhen commented Jul 7, 2020

每日一题会在下午四点在交流群集中讨论,五点 Github、交流群同步更新答案

答案

前置知识: 依赖收集、虚拟 DOM、响应式系统

现代前端框架有两种方式侦测变化,一种是 pull ,一种是 push

pull: 其代表为React,我们可以回忆一下React是如何侦测到变化的,我们通常会用setStateAPI显式更新,然后React会进行一层层的Virtual Dom Diff操作找出差异,然后Patch到DOM上,React从一开始就不知道到底是哪发生了变化,只是知道「有变化了」,然后再进行比较暴力的Diff操作查找「哪发生变化了」,另外一个代表就是Angular的脏检查操作。

push: Vue的响应式系统则是push的代表,当Vue程序初始化的时候就会对数据data进行依赖的收集,一但数据发生变化,响应式系统就会立刻得知。因此Vue是一开始就知道是「在哪发生变化了」,但是这又会产生一个问题,如果你熟悉Vue的响应式系统就知道,通常一个绑定一个数据就需要一个Watcher(具体如何创建的Watcher可以先了解下Vue双向数据绑定的原理如下图)

vue 双向数据绑定原理

一但我们的绑定细粒度过高就会产生大量的Watcher,这会带来内存以及依赖追踪的开销,而细粒度过低会无法精准侦测变化,因此Vue的设计是选择中等细粒度的方案,在组件级别进行push侦测的方式,也就是那套响应式系统,通常我们会第一时间侦测到发生变化的组件,然后在组件内部进行Virtual Dom Diff获取更加具体的差异,而Virtual Dom Diff则是pull操作,Vue是push+pull结合的方式进行变化侦测的。

@ghost
Copy link

ghost commented Oct 30, 2020

这题回答的内容还是太全面 感觉没理解透 希望可以更新答案 获取更一步的学习

@xsfxtsxxr
Copy link

我觉得双向数据绑定只是检测数据data的变化,而虚拟DOM是真正实现DOM更新的,这两个东西的职责完全不同的,缺一不可。所以不存在为什么还要用Vdom diff.

---一个菜鸡的浅显之见

@qzruncode
Copy link

笑哭,这种问题也有问的,一个dom节点发生改变vue的响应式机制可以直接修改就行了,如果直接修改一个数组或者直接切换一个组件呢?这里面肯定有的数据没变有的数据变了,有的组件是复用的有的是没复用的,这个时候就要用diff。就是两种场景而已。react�都是同理...

@RobinTan1024
Copy link

这问题确实奇怪,我猜面试官的意思是:假设有一个 input ,通过 v-model 双向绑定了 data.form.value ,当 data.form.value 的 setter 触发时,直接操作 dom:input.value = mValue 就行了,为啥还需要 vdom ?

答案:
1)应用不可能只有表单控件值改变,还有其他的元素的改动,难道也要在 setter 里面自己做吗?MVVM 重回 MVC
2)vdom 实现的批量 dom 更新可以提供一个可靠的 dom 改动性能下限
3)代码维护性天壤之别

@Florenceliyi
Copy link

上面的解释是不是有点问题,如果vue一开始就知道在哪发生变化,那它根本不用做diff算法,直接触发元素更新就行了,还是说这边解释的还不太完整。

@GoldenSide
Copy link

GoldenSide commented Sep 2, 2021

数据劫持准确的来说不是探测的真实dom上的属性变化,而是触发的订阅器中的对应的订阅者,所以当真实的dom改变的时候,走的是依旧是使用patch方法 进行diff 运算,然后才更新的dom ,
只是订阅者在内存中开发者和用户都察觉不到,另外这个patch 响应的时间足够短(因为diff算法利用的是元素复用原则),所有给人造成的错觉,错误的以为响应变化的载体与承接体都是真实dom
image

@hangaoke1
Copy link

早期的vue在没有引入虚拟dom的时候就是这么实现的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Vue teach_tag
Projects
None yet
Development

No branches or pull requests

7 participants