• vuereact 虚拟dom 区别


     感谢: 蜗牛老湿的分析

    Vue1.x

    没有 vdom,完全的响应式,每个数据变化,都通过响应式通知机制来新建 Watcher干活,就像独立团规模小的时候,每个战士入伍和升职,都主动通知咱老李,管理方便

    项目规模变大后,过多的 Watcher,会导致性能的瓶颈

     

     

     

     

     

     

    React15x

    而 React15时代,没有响应式,数据变了,整个新数据和老的数据做 diff,算出差异 就知道怎么去修改 dom了,就像老李指挥室有一个模型,每次人事变更,通过对比所有人前后差异,就知道了变化, 看起来有很多计算量,但是这种 immutable的数据结构对大型项目比较友好,而且 Vdom抽象成功后,换成别的平台render成为了可能,无论是打鬼子还是打国军,都用一个 vdom模式

    碰到的问题一样,如果 dom节点持续变多,每次 diff的时间超过了 16ms,就可能会造成卡顿(60fps)

     

     

    Vue2.x

    引入vdom,控制了颗粒度,组件层面走watcher通知, 组件内部走vdom做diff,既不会有太多watcher,也不会让vdom的规模过大,diff超过16ms,真是优秀啊 就像独立团大了以后,只有营长排长级别的变动,才会通知老李,内部的自己diff管理了

     

     

    React 16 Fiber

    React走了另外一条路,既然主要问题是 diff导致卡顿,于是 React走了类似 cpu调度的逻辑,把 vdom这棵树,微观变成了链表,利用浏览器的空闲时间来做 diff,如果超过了 16ms,有动画或者用户交互的任务,就把主进程控制权还给浏览器,等空闲了继续,特别像等待女神的备胎

     

     

    diff的逻辑,变成了单向的链表,任何时候主线程女神有空了,我们在继续蹭上去接盘做 diff,大家研究下 requestIdleCallback就知道,从浏览器角度看 是这样的

     

     

    大概代码

    1. requestIdelCallback(myNonEssentialWork);
    2. // 等待女神空闲
    3. function myNonEssentialWork (deadline){
    4. // deadline.timeRemaining()>0 主线程女神还有事件
    5. // 还有diff任务没算玩
    6. while(deadline.timeRemaining()>0&& tasks.length >0){
    7. doWorkIfNeeded();
    8. }
    9. // 女神没时间了,把女神还回去
    10. if(tasks.length >0){
    11. requestIdleCallback(myNonEssentialWork);
    12. }
    13. }

     

    Vue3

    这里的静态提升和事件缓存刚才说过了,就不说了,其实我也很纳闷,这些静态标记和事件缓存, React本身也可以做,为啥就不实现了,连 shouldComponentUpdate都得自己定义,为啥不把默认的组件都变成 pure或者 memo呢,唉,也许这就是人生把

    React给你自由, Vue让你持久,可能也是现在国内Vue和React都如此受欢迎的原因把

    Vue3通过 Proxy响应式+组件内部 vdom+静态标记,把任务颗粒度控制的足够细致,所以也不太需要 time-slice了。

     

     

    diff算法补充:

    dom的更新策略不同
    react 会自顶向下全diff.
    vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
    1. 在react中,当状态发生改变时,组件树就会自顶向下的全diff, 重新render页面, 重新生成新的虚拟dom tree, 新旧dom tree进行比较, 进行patch打补丁方式,局部跟新dom. 所以react为了避免父组件跟新而引起不必要的子组件更新, 可以在shouldComponentUpdate做逻辑判断,减少没必要的render, 以及重新生成虚拟dom,做差量对比过程.
    2. 在 vue中, 通过Object.defineProperty 把这些 data 属性 全部转为 getter/setter。同时watcher实例对象会在组件渲染时,将属性记录为dep, 当dep 项中的 setter被调用时,通知watch重新计算,使得关联组件更新。

    Diff 算法借助元素的 Key 判断元素是新增、删除、修改,从而减少不必要的元素重渲染。

    基于Diff的开发建议

    1、基于tree diff:

    (1)开发组件时,注意保持DOM结构的稳定;即尽可能少地动态操作DOM结构,尤其是移动操作。

    (2)当节点数过大或者页面更新次数过多时,页面卡顿的现象会比较明显。这时可以通过 CSS 隐藏或显示节点,而不是真的移除或添加 DOM 节点。

    2、基于component diff:

    (1)注意使用 shouldComponentUpdate() 来减少组件不必要的更新。

    (2)对于类似的结构应该尽量封装成组件,既减少代码量,又能减少component diff的性能消耗。

    3、基于element diff:

    (1)对于列表结构,尽量减少类似将最后一个节点移动到列表首部的操作,当节点数量过大或更新操作过于频繁时,在一定程度上会影响渲染性能。

    (2)循环渲染的必须加上key值,唯一标识节点


  • 相关阅读:
    [背包问题][二进制优化] Jzoj P4224 食物
    [并查集][排序] Jzoj P4223 旅游
    [哈夫曼树][优先队列] Bzoj P4198 荷马史诗
    [hash][差分][虚树] Jzoj P6011 天天爱跑步
    [dp] Jzoj P6012 荷马史诗
    [dp][递归] Jzoj P4211 送你一棵圣诞树
    [数学] Jzoj P3912 超氧化钾
    堆学习笔记(未完待续)(洛谷p1090合并果子)
    [AC自动机]luogu P2444 病毒
    [概率期望][DP]luogu P3830 随机树
  • 原文地址:https://www.cnblogs.com/leolovexx/p/15929530.html
Copyright © 2020-2023  润新知