React 与 Vue 框架的设计思路大 PK

全栈前端精选

共 3902字,需浏览 8分钟

 ·

2021-03-27 15:34

正文如下

本文是第十七届 - 前端早早聊框架专场,也是早早聊第 122 场,来自开课吧 - 大圣 的分享

关于我

大家好我是花果山的大圣,今天很荣幸,有机会跟大家分享一下很多年轻人感兴趣的话题《 Vue 和 React 设计思想 PK》,个人水平有限,如果有理解不到位的请倾盆,大家看完后并且再去 Vue 和 React 源码里探索一番,一定会有所收获, 如果没时间的话,还可以跟我一起早起学习

  1. Github
  2. B站
  3. 掘金

框架总览

前端框架繁多,在学习的时候也会陷入困惑,我们应该抓住最主流的内容 Vue/React,深入底层,尝试揣摩框架作者的设计思路,开阔自己的视野,大家也不要把自己限制在框架之中,认为工作中用到 Vue,就觉得 React 学起来没用,有些时候我们学习竞品的框架,是为了更好的认识自己在用的框架,废话不多说,由于 Vue 本身是个中庸的框架,再揪出设计思路理念比较极致的 Angular 和 Svelte,我们先从视图层最火的四大框架看一下

下载量

对比维度

我们从多个维度去对比前端的框架,就能看清楚现在各个框架的现状,我们学习每个框架的设计范式,并且尝试打破局限,就像猪八戒一样,出了高老庄,一路好风光

框架发展

字符串模板

想看清现在视图层的现状,要简单的看下之前框架的发展路线,JQuery 时代的渲染层,大部分都是基于字符串的模板,典型的框架就是 Underscore,baiduTemplate。大致的原理就是把 template 解析成一个函数,缺点也很明显,就是每次数据变化,模板内部要全部重新渲染

然后刚才我说的四个框架占领了现在的 Web 领域,核心的目标都是一样的,为了做出性能更好的 Web 应用,为此各路大神八仙过海,各显神通有这么几个宏观的维度

原生 VS 抽象

原生的就是 JavaScript 本身,比如 JQuery 基本没有太多的抽象,一个 $ 打天下,React 抽象程度稍微复杂一些,需要理解 Component, State, Hooks, JSX 等概念就可以上手了,抽象比较多的就是 Angular,上手就需要了解十几个概念,学习曲线很陡峭, Vue 就处在 React 和 Angular 中间,了解完 data,methods,单文件组建后就可以上手了

运行时 VS 预编译

另外一个维度就是运行时和预编译这个维度,所谓运行时,在浏览器内存里进行的任务,React 的 Runtime 比较重一些,数据发生变化后,并没有直接去操作 dom,而是生成一个新的虚拟 dom,并且通过 diff 算法得出最小的操作行为,全部都是在运行时来做的

这个维度的另外一个极端,也就是重编译的框架,在上线之前经过通过工程化的方式做了预处理,典型代表就是Svelte,基本上是一个 Compiler Framework,写的是模板和数据,经过处理后,基本解析成了原生的 dom 操作,Svelte 的性能也是最接近原生 js 的

Vue 依然处于比较中庸的地位,在运行时和预编译取了一个很好地权衡,保留了虚拟 dom,通过响应式控制虚拟 dom 的颗粒度,在预编译里又做了足够多的性能优化,做到了按需更新,这个一会再细聊

框架设计的维度

Vue 和 React

然后我们揪出来 Vue 和 React,有一些更细化维度

可变数据 VS 不可变数据

Vue1 就是把响应式数据玩出了花,通过拦截操作,修改一个数据的同时收集依赖,然后数据修改的时候去通知更新 dom,体验很是舒爽,我们修改了一个 JavaScript 的对象,视图层就修改好了, 这是 Vue 的黑魔法,React 的虚拟 Dom 创建之日期,就是通过计算新老数据的 diff,去决定操作那些 dom,所以每次修改数据,需要生成一份新的数据,说不上优劣之分,只不过路线不同

这大概就是 Vue 和 React 修改数据的代码对比

权衡

随着应用越来越复杂,React15 架构中,dom diff 的时间超过 16.6ms,就可能会让页面卡顿,Vue1 中的监听器过多,也会让性能雪崩,为了解决这个问题,Vue 选择了权衡,以组件作为颗粒度,组件层面用响应式通知,组件内部通过 dom diff 计算 ,既控制了应用内部 Watcher 的数量,也控制了 dom diff 的量级。看到这段实现的时候,不仅高呼,真是妙啊

  registerComponentHook(componentId, 'lifecycle''attach', () => {
    callHook(vm, 'beforeMount')

    const updateComponent = () => {
      vm._update(vm._vnode, false)
    }
    new Watcher(vm, updateComponent, noop, nulltrue)

    vm._isMounted = true
    callHook(vm, 'mounted')
  })

预编译和运行时

相关概念刚才已经科普了,在 Vue 和 React 中的体现,主要体现在 JSX 和 template 的区别上,React 是完全的 JSX,可以 JSX 在里面写 JavaScipt,所以特点就是足够的动态,与之对应的就是 Vue 的 template,template 的特点是语法受限,可以执行的语法技术 v-if v-for 等指定的语法,虽然不够动态,但是由于语法是可便利的,所以可以再预编译层面做更多的预判,让 Vue 在运行时有更好的性能

顺便放两张尤大的 ppt 的图,Vue3 通过在预编译阶阶段做静态标记的优化,做到了按需更新

  1. 纯静态的元素标记,直接越过 diff 阶段  比如 <p>hello</p>
  2. 静态的属性也会标记,在 diff 的时候越过这个属性的判断
  3. 事件函数传递的时候回加上缓存
  4. v-ifv-for 内部通过 block+ 数组的方式维护动态元素

时间切片

Vue3 通过静态标记 + 响应式 + 虚拟 dom 的方式,控制了 diff 的颗粒度,让 diff 的时间不会超过 16ms,但是 React 自上而下的 diff 过程,项目大了之后,一旦 diff 的时间超过 16.6ms,就会造成卡顿,对此 React 交出的解决方案就是时间切片

简单的来说就是把 diff 的任务按照元素拆开,利用浏览器的空闲时间去算 diff,React 把各种优化的策略都留给了开发者,Vue 则是帮开发者做了很多优化的工作

设计思想演进

组合优于集成

这个思想设计模式里面就有定论,也是现在 hooks 和 composition 大行其道的原因,代码写出来也会更加易于维护,这个图可以很好地体现出可维护性上的变化

跨端

刚才我们讲了 Svelte 可以做到直接编译成 JavaScript,性能接近原生,这么优秀的思想,为什么 Vue 还要保留虚拟 dom 这个额外的 runtime 损耗呢,我觉得比较重要的一个答案就是跨端

虚拟 dom 除了可以用来计算最小的 diff 之外,另外一个重要的功能就是可以用 JavaScript 的对象来去描述一个 dom,这就是一个普通的对象,在跨端领域意义重大,视图层返回的是一个对象,渲染层可以调用不同平台的渲染 api 去绘制即可

复习

如上所述,请认真学习框架,并不只是为了面试,而是框架里的优秀思想和设计模式,汇集了顶尖开发者团队最优秀的思想, 多学习别人优秀的代码,开阔自己的视野, 闭门造车你会发现,很多自己的顿悟只是别人的基础

推荐书

最后推荐一本对我涨薪帮助最大的书《算法》第四版

算法和数据结构一直都是前端工程师进阶的拦路虎之一,这块内容比较成体系,JavaScript 相关的算法书过于简单,只能入门,不能帮你学会算法, 教材《算法导论》从数学的角度去推导算法,又太难,所以我推荐这本《算法》第四版,内容详实有插画,帮助系统的构架算法知识体系,书里用的是 Java,学习的时候正好用 JavaScript 实现一遍书里的例子,学完绝对是一个新的段位

当然,我最大的爱好除了王者,就是看书了,其实有很多书可以推荐,比如

  1. JavaScript 进阶的红黄绿三套书
  2. 怎么和 HR 谈钱的《谈判是什么》和《优势谈判》
  3. 和产品经理吹牛逼必备坛子 《浪潮之巅》《硅谷之谜》
  4. 《软技能2》
  5. 。。。。

以后有机会再给大家推荐,感谢大家的支持 ,我是大圣, 下期再见

浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报