15

前言

我们已经通过学习掌握了vue.js这个渐进式的JavaScript 框架,并且大致知道了React、Angular和Vue的区别,那么如何对这三个框架进行深层次的分析,更好地区分它们呢?我们可以从框架设计上入手试着分析它们。

什么是框架

可以参考我之前的文章关于基于框架搭建与布局系统的思考

框架设计

一、职责范围

职责范围就是框架设计之初要考虑的范围,是一手全包还是只封装底层核心代码?简单说就是这个框架可以为你做多少事情

1.small scope(小职责范围)

代表:React
(1)设计理念:
自底向上
只建立核心模型,然后围绕核心模型建立生态系统
(2)优点:
  • 初始时需要理解的概念很少

初始只用掌握核心代码

  • 灵活
    因为框架/库只提供了部分底层的原生实现,用户可以在框架基础上构建任意复杂的系统
  • 生态好

拥有强大的生态系统

  • 维护成本小
(3)缺点:
  • 学习成本大

1.同样也是因为框架只提供了部分底层的原生实现,所以当我们需要构建比较复杂的系统时,就需要用非常有限的、非常原始的一些东西,去构建一些复杂的想法。(如学习了React,还需钻研Redux、HOC 高阶组件、render、props、Hooks以及在 JS 中使用 CSS 的各种方式等等)
2.官方只提供基础的文档,其余需要自己去钻研,需要自主学习能力

2.large scope(大职责范围)

代表:Angular
(1)设计理念
自上而下
尽可能考虑用户可能会遇到的问题;当你尝试解决一个问题时,你在框架内就能找到解决方案。
(2)优点
  • 框架与生态一致性

集中式的设计确保了它本身与其生态系统的。当你遇到一个具体问题的时候,你不必去找一些不同的解决方案,你只需要看看框架它让你做什么,最大的可能就是它(框架)对此已经有解决方案。

  • 少量代码解决最常见的问题

可以通过构建抽象概念来解决最常见的问题,如只需要建一个路由、一个http请求数据就能实现基本功能。

(3)缺点
  • 更高的学习门槛

对于初学者来说,如果没有类似使用 Java 或者 C# 等语言经验的话,而是仅仅只学过 HTML/CSS 以及 JavaScript 的话,当你看到 Angular 文档的时候,你可能会很难吃透。

  • 不灵活

如果框架内置的解决方案不满足当前需求,但却没有方法替换。
当你想尝试更改底层想法时,它会影响到你项目中的每个组件(牵一发而动全身)。

3.progressive scope(渐进式框架)

代表:Vue
(1)设计理念
框架分层
允许以渐进的方式选择特性。如需要路由、需要状态管理就引入,不需要也不影响,按需取舍,既能开发全新应用,也能融合之前已开发应用
(2)优点
  • 降低了学习门槛
(3)缺点

作为small scope 和 large scope的中间者,需要去权衡利弊

  • 生态系统可能不会像小职责范围那样多样化
  • 维护负担几乎与大职责范围相同

二、渲染机制

如何表达你的视图层,框架如何处理代码?如何将实际渲染东西展示到页面上的?这就要考虑我们的渲染机制。

1.原生DOM

原生DOM大家都熟悉,在这里我就不过多说明了。

<div>
  <p class="framework-design">框架设计</p>
</div>
(1)优点
  • 易用性强
(2)缺点

在我们对原生DOM进行操作时,会发现很多缺点

  • 效率低
  • 解析速度慢
  • 内存占用量高

2.JSX / VDOM(虚拟DOM)

通过框架来表现自己的UI结构

render() {
    return h(
        'div',
        null,
        h(
            'p',
            {  'class': 'framework-design' },
           '框架设计'
        )
    );
}
(1)优点
  • 通过JS实现UI层,具有 JavaScript 的完整表现力
  • 将视图层视为数据,可以对数据做任何操作
  • 可以渲染到任何目标,终端、PDF、Canvas、WebGL
(2)缺点
  • VDOM 本身成本很高

即使你只有一个节点,也可能会触发 这个VDOM 的 Diff 算法

3.templates(模板编译)

通过模板来表现自己的UI结构

<template>
  <div>
    <p>{{ data.title }}</p>
    <p>{{ data.content }}</p>
  </div>
</template>
(1)优点
  • 更加直接的渲染指令,具有更好的原生性能

通过模板编译符准确知道可变的dom节点

<div>
  <p>框架设计</p>
  <p>{{ message }}</p>
</div>
(2)缺点
  • 受限于严格的模板语法,从而失去 JavaScript 的表达能力

三、状态机制

1.脏检查

脏数据:产生了变化的数据
脏检查:找出脏数据,重新渲染视图

那么在什么时候进行脏检查呢?检查哪些元素呢?

下面以Angular为例

何时进行

Angular 会在可能触发 UI 变更的时候进行脏检查。例如常用的 ng-click。

检查哪些元素

Angular 会对所有绑定到 UI 上的表达式做脏检查。在Angular程序初始化时,会将绑定的对象的属性添加为监听对象(watcher),也就是说一个对象绑定了N个属性,就会添加N个watcher。

如何操作

当脏检查触发,则会循环遍历所有watch,最后更新DOM

通俗点讲

我们回忆一下我们的学生时代,住校生都住在寝室里面,每栋宿舍楼都有专门的宿管阿姨。每天晚上快熄灯的时候(触发脏检查了),宿管阿姨开始巡逻了,她要看哪些学生还没回寝室呢,寝室有哪些违规现象呢。阿姨会从1楼开始一直巡逻查看到顶楼,每间宿舍都要查看(循环遍历watcher)。但是呢,因为目前顶楼还没住人,所以阿姨巡逻时会跳过(只检查绑定到UI上的表达式)。最后啊,没回寝的学生都被阿姨拿上小本本记下来了(查出了脏数据)。

2.依赖追踪

当某一个数据(依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动,也就是数据驱动。

下面以Vue为例

何时进行

依赖数据发生变化

如何操作

为数据定义 getter & setter
当在data里面定义了数据时,系统会为这些数据添加getter和setter
获取数据时触发getter,为数据赋值时触发setter
当触发了setter时,model发生变化,系统会通知所有的viewModel更新视图

通俗点讲

在我们大学时期,上课还是相对而言较严格的,为了应对各项严格的规章制度,417寝室的室友们商量拉了一个微信群(依赖数据:微信群),当有重大事情时在群里面进行通知(每个人都可以接收消息、发送消息 getter & setter)。

某天政治课,大家偷懒赖床不去上课,只有小李一人去了教室,不一会儿,小李就在微信群里面发了一句话“老师在点名!速来!”(set,更改了model,通知了所有的viewModel)。接收到消息的所有室友迅速起床飞奔去教室(监听到依赖数据发生变化,自动更新视图)。

3.VDOM diff

保存上次的VDOM,对比这次的VDOM,发现差异,更改视图
下面以React为例

何时进行

state 发生改变

如何操作

比较两次的VDOM,层层遍历,找出不同的数据,更新整个DOM

通俗点讲

大学每年最痛苦的就是期末了,期末时各个同学打起十二分的精神,抢占各个楼道口,通宵达旦的背书看题。这个时候少不了老师划的重点,政治课老师划完重点后,小熊还不放心,去找上一届的学长讨来了学长那一届的重点,回到寝室就开始一章一章地对比,从书的第一页翻到了最后一页(比较两次VDOM),把不同的地方都标记出来(找出不同的数据),最后把比较过后的整本书都背了下来(更新整个DOM)。

总结

通过以上我们可以看出

1.React

是自底向上的框架。
它只提供部分底层的原生实现,拥有强大的生态环境。
使用JSX / VDOM 来渲染视图层。
使用VDOM diff更新视图,通常整个DOM都要重新渲染过。
学习成本很高,虽然初始上手很快,但如果想要实现更为复杂的系统,需要钻研Redux、HOC 高阶组件、render、props、Hooks等知识。

2.Angular

是自上而下的框架。
使用templates和JSX / VDOM实现视图层。
采用脏检查更新视图,设置多个watcher,当watcher越多时会耗费性能。
学习门槛高,不利于初学者。
组件丰富,一般常见的功能都在框架里能找到解决方案。
二次开发成本高,当想实现底层想法时,会影响很多组件。

3.Vue

渐进式框架。
使用templates和JSX / VDOM实现视图层。
采用数据驱动更新视图,有变化才更新,提升效率。
易上手,灵活性强,既能开发全新应用,又能融合进已有应用中。
性能高,超快虚拟DOM

Reachel
2.6k 声望219 粉丝