• 怎么更好的理解虚拟DOM?


    虽然Virtual DOM确实是性能杠杠的,但是其实可以说它是无心插柳的一个结果。

    React的核心思想:
    一个Component拯救世界,忘掉烦恼,从此不再操心界面。

    1. Virtual Dom快,有两个前提
    1.1 Javascript很快
    Chrome刚出来的时候,在Chrome里跑Javascript非常快,给了其它浏览器很大压力。而现在经过几轮你追我赶,各主流浏览器的Javascript执行速度都很快了。
    Julia有一个Benchmark,Julia Benchmarks, 可以看到Javascript跟C语言很接近了,也就几倍的差距,跟Java基本也是一个量级。
    所以说,单纯的Javascript其实速度是很快的。
    多说一句,这种benchmark并不是绝对的依据,因为用这个语言写这个跑得快,并不代表一定是用这个语言写那个也跑得快。

    1.2 DOM很慢
    关于什么CSS,什么layout那些我不懂,就不瞎说了,咱就说说DOM的结构。
    当你用document.createElement()创建一个空的Element的时候(比如创建一个空的div),有以下这几页的东西需要实现(当然,这不是标准,只是个大概的意思):
    HTMLElement - Web API Interfaces
    Element - Web API Interfaces
    GlobalEventHandlers
    非常非常多,并且还有不少嵌套引用。
    你可以在Chrome console里手动调用document.createElement 然后插入DOM里看看效果。
    这还是一个空的Elemnt,啥内容也没有,就这么复杂。所以说DOM的操作非常慢是可以理解的。不是浏览器不想好好实现DOM,而是DOM设计得太复杂,没办法。

    而更糟糕的是,我们(以及很多框架)在调用DOM的API的时候做得不好,导致整个过程更加的慢。React的Virtual Dom解决的是这一部分问题,它并不能解决DOM本身慢的问题。
    比如说,现在你的list是这样,
    <ul>
    <li>0</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    </ul>
    你想把它变成这样
    <ul>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    </ul>
    通常的操作是什么?
    先把0, 1,2,3这些Element删掉,然后加几个新的Element 6,7,8,9,10进去,这里面就有4次Element删除,5次Element添加。
    而React会把这两个做一下Diff,然后发现其实不用删除0,1,2,3,而是可以直接改innerHTML,然后只需要添加一个Element(10)就行了,这样就是4次innerHTML操作加1个Element添加,比9次Element操作快多了吧?

    当然还有其它一些例子能够优化我们对DOM的操作,就不举例子了。(实际上是因为我举不出例子。。。)

    2. 关于React
    2.1 接口和设计
    在React的设计里,是完全不需要你操作DOM的。在React里其实根本就没有DOM这个概念的存在,只有Component。当你写好一个Component以后,Component会完全负责UI,你不需要也不应该去也不能够指挥Component怎么显示,你只能告诉它你想要显示一个香蕉还是两个梨。
    隔离DOM并不是因为DOM慢(当然DOM确实慢),而是把界面和业务完全隔离,操作数据的只关心数据,操作界面的只关心界面。可以想象成把MVC里面的Controller分成两个部分,一部分合并到M里面去,一部分合并到V里面去,就剩下MV,没有C了。。。其实M也并不是Model了。推荐看一下Pete Hunt的这个Talk 

    重复一遍,React的意思是,我提供一个Component,然后你只管给我数据,界面的事情完全不用你操心,我保证会把界面变成你想要的样子。
    你可以把一个React的Component想象成一个Pure Function,只要你给的数据是[1, 2, 3],我保证显示的是[1, 2, 3]。没有什么删除一个Element,添加一个Element这样的事情。NO。你要我显示什么就给我一个完整的列表。

    说到这里,插一句别的,我一开始看到这里还以为这样的处理方式比较适合一般的WEB应用,写游戏啊什么的可能这个模式不太好用,然后我就看到Pete Hunt那个Talk,说DOOM 3就是这么干的。

    。。
    。。。
    眼泪都下来了,大神们的思路果然我是摸不着边的,洗洗睡吧。

    睡醒了接着说。React其实需要从Imperative Programming转换到Declarative Programming去理解。你不要一步一步告诉我这件事情怎么做,什么先和面再剁馅,NO,告诉我你想要煎饼还是月饼,我会想办法去做的,不要来干扰我。你只需要告诉我有这么一个列表[1, 3, 6]需要显示就行了,不要告诉我怎么显示,我会想办法的,我保证美得冒泡,各种神奇的效果,亮瞎你的钛合金狗眼。

    行了行了,你真啰嗦。

    。。。

    再说几句瞎扯的话,Flux虽然说的是单向的Data Flow,但是实际上就是单向的Observer。
    Store->View->Action->Store(箭头是数据流向,实现上可以理解为View监听Store,View直接trigger action,然后Store监听Action)
    等等,不是说Component是pure function不跟谁绑定吗,为啥View要监听Store?你这个骗子。怪不得都没有人给你点赞。
    。。。
    。。

    我们还是继续说React把,Flux是什么鬼,我反正没听过。


    2.2 实现
    OK,那么,如何实现React呢?
    其实对于React来说,最容易实现的办法是每次完全摧毁整个DOM,然后重新建立一个全新的DOM。因为一个Component是一个Pure function,根本就没有State这个概念,我又不知道DOM现在是什么样子,那最简单的办法当然是只要你给新数据,我就把整个DOM删了,然后根据你给的数据重新生成一个DOM咯。

    等等,Virtual DOM哪儿去了?

    事实是这样的,最简单实现React的方式虽然说非常简单,但是效率实在是太低了,你居然要全部都删了重建DOM,DOM本身已经很慢了,你还这么去用,谁能忍啊?

    然后Virtual DOM就来救场了。

    Virtual DOM和DOM是啥关系呢?
    首先,Virtual DOM并没有完全实现DOM,Virtual DOM最主要的还是保留了Element之间的层次关系和一些基本属性。因为DOM实在是太复杂,一个空的Element都复杂得能让你崩溃,并且几乎所有内容我根本不关心好吗。所以Virtual DOM里每一个Element实际上只有几个属性,并且没有那么多乱七八糟的引用。所以哪怕是直接把Virtual DOM删了,根据新传进来的数据重新创建一个新的Virtual DOM出来都非常非常非常快。(每一个component的render函数就是在做这个事情,给新的virtual dom提供input)

    所以,引入了Virtual DOM之后,React是这么干的:
    你给我一个数据,我根据这个数据生成一个全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去 diff,得到一个Patch,然后把这个Patch打到浏览器的DOM上去。完事。

    有点像版本控制打patch的思路。
    假设在任意时候有,VirtualDom1 == DOM1 (组织结构相同)
    当有新数据来的时候,我生成VirtualDom2,然后去和VirtualDom1做diff,得到一个Patch。
    然后将这个Patch去应用到DOM1上,得到DOM2。
    如果一切正常,那么有VirtualDom2 == DOM2。

    这里你可以做一些小实验,去破坏VirtualDom1 == DOM1这个假设(手动在DOM里删除一些Element,这时候VirtualDom里的Element没有被删除,所以两边不一样了)。
    然后给新的数据,你会发现生成的界面就不是你想要的那个界面了。


    最后,回到为什么Virtual Dom快这个问题上。
    其实是由于每次生成virtual dom很快,diff生成patch也比较快,而在对DOM进行patch的时候,我能够根据Patch的内容,优化一部分DOM操作,比如之前1.2里的那个例子。
    重点就在最后,哪怕是我生成了virtual dom,哪怕是我跑了diff,但是我根据patch简化了那些DOM操作省下来的时间依然很可观。所以总体上来说,还是比较快。

    简单发散一下思路,如果哪一天,DOM本身的已经操作非常非常非常快了,并且我们手动对于DOM的操作都是精心设计优化过后的,那么加上了VirtualDom还会快吗?
    当然不行了,毕竟你多做了这么多额外的工作。

    但是那一天会来到吗?
    诶,大不了到时候不用Virtual DOM。

  • 相关阅读:
    从Active Directory中获取用户信息
    BindingNavigator & BindingSource Classes in VS2005
    New patterns & practices for Visual Studio 2005 and .NET 2.0
    Logging application block of Enterprise Library 2.0
    Pocket C# Project
    Enterprise Library 1.0 HandsOn Labs
    Visual Studio 2005 Team System Technical Articles from MSDN
    Web Services Enhancements (WSE) 3.0 Released!
    更新Active Directory/Exchange Address Book的小工具
    Android 菜单项选项
  • 原文地址:https://www.cnblogs.com/daqianduan/p/4759562.html
Copyright © 2020-2023  润新知