Skip to content

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

@Genzhen

Description

@Genzhen
Collaborator
No description provided.

Activity

changed the title [-]既然 Vue 通过数据劫持可以精准探测数据在具体dom上的变化,为什么还需要虚拟 DOM diff 呢?[/-] [+]Day92:既然 Vue 通过数据劫持可以精准探测数据在具体dom上的变化,为什么还需要虚拟 DOM diff 呢?[/+] on Jul 7, 2020
Genzhen

Genzhen commented on Jul 7, 2020

@Genzhen
CollaboratorAuthor

每日一题会在下午四点在交流群集中讨论,五点 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

ghost commented on Oct 30, 2020

@ghost

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

xsfxtsxxr

xsfxtsxxr commented on Dec 18, 2020

@xsfxtsxxr

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

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

qzruncode

qzruncode commented on Apr 15, 2021

@qzruncode

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

RobinTan1024

RobinTan1024 commented on May 15, 2021

@RobinTan1024

这问题确实奇怪,我猜面试官的意思是:假设有一个 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

Florenceliyi commented on Jun 30, 2021

@Florenceliyi

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

GoldenSide

GoldenSide commented on Sep 2, 2021

@GoldenSide

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

hangaoke1

hangaoke1 commented on Sep 6, 2021

@hangaoke1

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Vueteach_tag

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @Genzhen@hangaoke1@qzruncode@GoldenSide@xsfxtsxxr

        Issue actions

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