V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
thomasyim
V2EX  ›  程序员

写了一个小白都能看懂的 Virtual DOM 实现

  •  2
     
  •   thomasyim ·
    cyan33 · 2018-03-25 01:15:47 +08:00 · 4934 次点击
    这是一个创建于 2440 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不知不觉已经是 2018 年了,从接触 React 开始也两年了,但是一直没有勇气深入研究源码。

    然而去年有幸拿到了 FB 的实习,所以给了自己一个强迫去学习的理由。一个月硬读下来,感觉还是很有收获的。

    学习过程中边写博客边重复造轮子,写了两个项目。

    第一个是 learn-react-source-code,是我在 Paul 2016 年 React Rally Talk 上的 build react from scratch 的基础上做了一部分简化、改进后写的一个项目,同时我也(很认真地)写了 6 篇博客,讲了一下我对核心部分的理解。

    第二个是 v-dom,用不到 200 行代码实现了一个 Virtual DOM。Virtual DOM 这个名字让我一开始望而生畏,但是在真正学习理解之后,发现它其实就是一个非常简洁的映射思路。我相信只要有基本的 JS 基础,大家在一定时间内都能读懂这个项目的代码。

    从很多朋友那里已经收到了对这两个项目还不错的评价,所以才斗胆来分享一下,祝大家读完有所收获。

    同时也宣传一下自己在知乎的专栏

    求个 Star。

    以上。

    20 条回复    2018-03-27 12:02:43 +08:00
    TabGre
        1
    TabGre  
       2018-03-25 06:33:41 +08:00 via iPhone   ❤️ 1
    厉害,跟进学习
    hardman
        2
    hardman  
       2018-03-25 07:41:51 +08:00 via Android   ❤️ 1
    了解学习下
    xuanyuanaosheng
        3
    xuanyuanaosheng  
       2018-03-25 08:06:36 +08:00 via Android
    学习一下
    binux
        4
    binux  
       2018-03-25 08:23:52 +08:00
    于是我每次在 ul 列表中,交替 prepend 一个 text node 一个 li,就能导致你的 v-dom 不断 replace 整个 ul 了吗?
    thomasyim
        5
    thomasyim  
    OP
       2018-03-25 08:49:25 +08:00
    @binux 是的 minimal update。这一点你可以在每次 setState 的时候看审查元素,只有“在变动”的元素在变化
    xor
        6
    xor  
       2018-03-25 09:05:30 +08:00 via iPhone
    minimum update 需要 tree diff 算法,光这个算法就不只 200 行了吧
    binux
        7
    binux  
       2018-03-25 09:16:19 +08:00
    @thomasyim 本来只要在 ul 里 prepend 一个元素就可以了,你现在把整个 ul 都重建了,这也叫 minimal update ?
    lance6716276
        8
    lance6716276  
       2018-03-25 10:06:35 +08:00 via Android
    老哥啊,你还上 v2ex
    qiuyk
        9
    qiuyk  
       2018-03-25 10:54:37 +08:00
    之前我闲的蛋疼也写了一个 23333 https://github.com/Siubaak/kut
    qiuyk
        10
    qiuyk  
       2018-03-25 11:05:27 +08:00
    @binux 个人觉得其实算是 react 一个没做好的地方(当然楼主的做法参考了 react ),就是十分不建议在列表头部插入一个元素,会引起之前所有节点的移动。
    ahonn
        11
    ahonn  
       2018-03-25 11:50:13 +08:00
    @qiuyk #10 你知道列表项的 key 是干嘛用的么..
    qiuyk
        12
    qiuyk  
       2018-03-25 12:19:49 +08:00
    @ahonn 知道的 你可以先看下这篇文章 https://zhuanlan.zhihu.com/p/20346379 react 的做法我叫前向 diff 我自己实现加入了后向 diff 并取前向 diff 和后向 diff 的 patches 较小值来更新节点 就不会有这个问题
    thomasyim
        13
    thomasyim  
    OP
       2018-03-25 13:00:24 +08:00 via iPhone
    @binux 我并没有重新 mount 呀:)
    thomasyim
        14
    thomasyim  
    OP
       2018-03-25 13:00:34 +08:00 via iPhone
    @lance6716276 哈哈哈哈哈哈哈
    thomasyim
        15
    thomasyim  
    OP
       2018-03-25 13:01:25 +08:00 via iPhone
    @lance6716276 哈哈哈哈哈哈哈是你
    thomasyim
        16
    thomasyim  
    OP
       2018-03-25 13:27:15 +08:00 via iPhone
    @qiuyk 棒👍
    binux
        17
    binux  
       2018-03-25 13:30:15 +08:00 via Android
    @thomasyim 你都 replace 了,还说没有
    thomasyim
        18
    thomasyim  
    OP
       2018-03-25 13:33:34 +08:00 via iPhone
    @binux 麻烦你自己好好读代码 再不然就 console 一下再来说好吗? element type 不变的话 是不会进那个 flow 的
    binux
        19
    binux  
       2018-03-25 13:55:58 +08:00 via Android
    @thomasyim 我都说了交替插入 text node 和 li
    thomasyim
        20
    thomasyim  
    OP
       2018-03-27 12:02:43 +08:00
    @binux 不好意思之前没理解你说的什么意思。你说的这个问题即使是在 React 也确实是存在的,直接去看 [React Reconcilliation]( https://reactjs.org/docs/reconciliation.html) 就会有答案。这也是 @qiuyk 上面评论里说的问题。从这个意义上来说 确实不是 minimal update
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2763 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:40 · PVG 23:40 · LAX 07:40 · JFK 10:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.