大家好,我是卡颂。

都说中国人考究中庸之道,中国人造的框架考究么?

本文会从原理层面解说Vue是如何在运行时与编译时之间放弃中庸的均衡。

UI = fn(state)

简直所有前端框架工作原理都能用如下公式概括:

UI = fn(state)

UI(视图)能够通过state(状态)通过fn(框架)计算得出。

然而具体原理上,框架之间却千差万别。

能够依照更新粒度将他们分为三类:

  • 树级更新
  • 组件级更新
  • 节点级更新
更新粒度没有优劣之分,只是对应不同的实现

接下来咱们简略理解下不同粒度更新形式的实现原理。

假如有如下组件树,其中Cpn是一个自定义组件,内部结构为ul>li*2

咱们心愿将Cpn内的一个li更新为黄色:

树级更新

树级更新的框架会再生成一棵残缺虚构DOM树,生成过程中与之前的虚构DOM树对应节点进行比拟:

找到变动的节点后,执行对应DOM操作。

树级更新框架的特点是:

  • 依赖虚构DOM
  • 不关怀触发更新的节点(因为会通过虚构DOM的全树比照找到他)

采纳这种更新形式最有名的框架就是React

组件级更新

下面的例子,如果是组件级更新框架。

会找到触发更新节点所在组件,生成该组件的虚构DOM树(而不是全树的虚构DOM树),生成过程中与该组件之前的虚构DOM树对应节点进行比拟:

找到变动的节点后,执行对应DOM操作。

组件级更新框架的特点是:

  • 依赖虚构DOM
  • 关怀触发更新的节点(虚构DOM的比照会作用于该节点所在组件)

采纳这种更新形式最有名的框架就是Vue

节点级更新

如果是节点级更新框架,在编译时会依据状态变动对应的DOM变动间接生成对应办法,当状态扭转后间接调用对应办法。

下面的例子,在编译时会关联color状态与changeColor办法:

function changeColor(newColor) {  li.style.color = newColor;}

当扭转color状态后间接调用changeColor办法更新li对应DOM

节点级更新框架的特点是:

  • 不依赖虚构DOM,依赖预编译(建设状态与扭转DOM的办法之间的分割)
  • 关怀触发更新的节点(节点状态与更新办法一一对应)

采纳这种更新形式最有名的框架就是Svelte

中庸的Vue3

Vue作为组件级更新代表,更新粒度介于树级节点级之间。那到底是两头偏左呢,还是两头偏右呢?

Vue3说:

我要重复横跳,两边我都要

Vue3中蕴含三种树状构造:

形容视图的树 -> 虚构DOM树 -> 实在DOM树

其中形容视图的树官网举荐应用模版语法,但也能应用JSX

不论是哪种形式,最终都会转化为虚构DOM树

当应用JSX时,Vue3领有了React运行时的灵活性,此时的Vue3能够看作是加强版React + Mobx

当应用模版语法Vue3引入了预编译技术。此时能够将Vue3的工作流程细化为四步:

形容视图的树 -> VNode树 -> Block数组 -> 实在DOM树

其中VNode树就是惯例意义的虚构DOM树Block数组则为VNode树中对状态有依赖,会变动的那局部VNode组成的数组。

比方,对于如下模版语法:

<template>  <section>    <div>i am</div>    <p>{{name}}</p>  </section></template>

sectiondiv不蕴含状态,不会变动,所以会转化为VNode,然而没有对应Block

p蕴含状态name,会转化为VNodeBlock

当该template所在组件触发name状态变动,之前须要顺次创立sectiondivpVNode并进行比拟。

有了预编译技术后只须要遍历Block数组进行比拟。

用上文的例子即只须要比照一个li节点:

在这种状况下,尽管是应用虚构DOM组件级更新框架,然而曾经很靠近节点级更新框架了。

总结

本文按更新粒度介绍了三种不同类型的框架,以及Vue3在抉择JSX模版语法时在灵活性与更新粒度间的灵便变动。

能够说是很合乎中庸之道了。

有人会问,应用Vue3的用户大部分都能承受模版语法,为什么不间接摈弃虚构DOM,应用预编译技术,实现真正的节点级更新

一方面,虚构DOM使框架脱离具体的视图层,更不便跨端渲染。

另一方面,Vue2社区生态积攒了大量基于虚构DOM的库。

如果是你,在这种状况下会作何抉择呢?