面试官:什么是虚拟DOM?如何实现一个虚拟DOM?

论坛 期权论坛     
选择匿名的用户   2021-5-22 15:16   13   0
<div id="js_content">
<p style="text-align: left"><img src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-c56e90a6691bcf3be70411ff7a4d1499"></p>
<h2>一、什么是虚拟DOM</h2>
<p>虚拟 DOM (<code>Virtual DOM</code> )这个概念相信大家都不陌生,从 <code>React</code> 到 <code>Vue</code> ,虚拟 <code>DOM</code> 为这两个框架都带来了跨平台的能力(<code>React-Native</code> 和 <code>Weex</code>)</p>
<p>实际上它只是一层对真实<code>DOM</code>的抽象,以<code>JavaScript</code> 对象 (<code>VNode</code> 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上</p>
<p>在<code>Javascript</code>对象中,虚拟<code>DOM</code> 表现为一个 <code>Object</code>对象。并且最少包含标签名 (<code>tag</code>)、属性 (<code>attrs</code>) 和子元素对象 (<code>children</code>) 三个属性,不同框架对这三个属性的名命可能会有差别</p>
<p>创建虚拟<code>DOM</code>就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟<code>DOM</code>对象的节点与真实<code>DOM</code>的属性一一照应</p>
<p>在<code>vue</code>中同样使用到了虚拟<code>DOM</code>技术</p>
<p>定义真实<code>DOM</code></p>
<pre class="blockcode"><code class="language-go">&lt;div id&#61;&#34;app&#34;&gt;
    &lt;p class&#61;&#34;p&#34;&gt;节点内容&lt;/p&gt;
    &lt;h3&gt;{<!-- -->{ foo }}&lt;/h3&gt;
&lt;/div&gt;
</code></pre>
<p>实例化<code>vue</code></p>
<pre class="blockcode"><code class="language-go">const app &#61; new Vue({
    el:&#34;#app&#34;,
    data:{
        foo:&#34;foo&#34;
    }
})
</code></pre>
<p>观察<code>render</code>的<code>render</code>,我们能得到虚拟<code>DOM</code></p>
<pre class="blockcode"><code class="language-go">(function anonymous() {
with(this){return _c(&#39;div&#39;,{attrs:{&#34;id&#34;:&#34;app&#34;}},[_c(&#39;p&#39;,{staticClass:&#34;p&#34;},
       [_v(&#34;节点内容&#34;)]),_v(&#34; &#34;),_c(&#39;h3&#39;,[_v(_s(foo))])])}})
</code></pre>
<p>通过<code>VNode</code>,<code>vue</code>可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作, 经过<code>diff</code>算法得出一些需要修改的最小单位,再更新视图,减少了<code>dom</code>操作,提高了性能</p>
<h2>二、为什么需要虚拟DOM</h2>
<p><code>DOM</code>是很慢的,其元素非常庞大,页面的性能问题,大部分都是由<code>DOM</code>操作引起的</p>
<p>真实的<code>DOM</code>节点,哪怕一个最简单的<code>div</code>也包含着很多属性,可以打印出来直观感受一下:<img src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-11c92d61a74d2d5d4a295ba0b221951d"></p>
<p>由此可见,操作<code>DOM</code>的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验</p>
<p><strong>举个例子:</strong></p>
<p>你用传统的原生<code>api</code>或<code>jQuery</code>去操作<code>DOM</code>时,浏览器会从构建<code>DOM</code>树开始从头到尾执行一遍流程</p>
<p>当你在一次操作时,需要更新10个<code>DOM</code>节点,浏览器没这么智能,收到第一个更新<code>DOM</code>请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程</p>
<p>而通过<code>VNode</code>,同样更新10个<code>DOM</code>节点,虚拟<code>DOM</code>不会立即操作<code>DOM</code>,而是将这10次更新的<code>diff</code>内容保存到本地的一个<code>js</code>对象中,最终将这个<code>js</code>对象一次性<code>attach</code>到<code>DOM</code>树上,避免大量的无谓计算</p>
<blockquote>
  <p>很多人认为虚拟 DOM 最大的优势是 diff 算法,减少 JavaScript 操作真实 DOM 的带来的性能消耗。虽然这一个虚拟 DOM 带来的一个优势,但并不是全部。虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种GUI</p>
</blockquote>
<h2>三、如何实现虚拟DOM</h2>
<p>首先可以看看<code>vue</code>中<code>VNode</code>的结构</p>
<p>源码位置:src/core/vdom/vnode.js</p>
<pre class="blockcode"><code class="language-go">export default class VNode {
  tag: string | void;
  data: VNodeData | void;
  children: ?Array&lt;VNode&gt;;
  text: string | void;
  elm: Node | void;
  ns: string | void;
  context: Component | void; // rendered in this component&#39;s scope
  functionalContext: Component | void; // only for functional component root nodes
  key: string | number | void;
  componentOptions: VNodeComponentOptions | void;
  componentInstance: Component | void; // component instance
  parent: VNode | void; // component placeholder node
  raw: boolean; // contains raw HTML? (server only)
  isStatic: boolean; // hoisted static node
  isRootInsert: bool
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP