Skip to main content

React和Vue到底哪个好

· 2 min read
wang bo
早睡早起

只要在前端交流♂群里,有人问vue好还是react好,必然会引起一波腥风血雨。

2020年JS框架性能对比.jpg

上图是Solid.js作者Ryan Carniato写的2020年JS框架性能对比,内含15张跑分表。

而这些跑分表里吊车尾的总是react,vue;

不是吧,不是吧,前端进步这么快,react,vue啥时候都这么拉了。

比较#

一般在跑分表中采用虚拟dom的框架性能普遍偏低。

像类似于Svelete这种: 预编译 + 细粒度更新 框架性能都很好

vue3 也是 预编译 + 细粒度更新 + 虚拟dom的

所以,在局部小改变上vue胜利。react更新会遍历整棵树。

反转#

react真有这么不堪吗?

react自从有了基于虚拟dom的时间切片以后,react能更进一步降低持续的可交互时间。

持续的可交互时间: 我们知道,JS可以操作DOM,GUI渲染线程与JS线程是互斥的。所以JS脚本执行和浏览器布局、绘制不能同时执行。 在每16.6ms时间内,需要完成如下工作:JS脚本执行 ----- 样式布局 ----- 样式绘制。当js执行时间过长,就没有时间执行样式布局和绘制了,体现到用户上,就是网页掉帧,卡顿。

react因为fiber架构的原因,Scheduler与Reconciler的工作都在内存中进行,只有当所有组件都完成Reconciler工作后,才会交给Renderer渲染。

vue2通过Object.defineProperty(),vue3通过proxy进一步降低了cpu和内存的开销。

vue模板语法和双向绑定react没有?#

与公司后端聊前端时,他们就会说vue会有模板语法,有双向绑定。

我的理解是:Vue中也可以使用jsx,同样jsx里也可以实现模板语法

<div r-if={visible}>    {content}</div>
        |        v
React.createElement(    'div',    {'r-if': visible},    content)
        |        v
if(visible){    React.createElement(        'div',        {'r-if': visible},        content    ) }

双向绑定是对表单来说的,表单的双向绑定,说到底也就是value的单项绑定 + onchange的一个语法糖。并不是react和vue理念上的真正体现。

单项数据流也是vue和react共同默契的选择,核心是为了避免组件自身(可复用)状态设计

1.react和vue理念上的差别#

我认为评价两个框架时应该从理念开始,以至于导致未来两个框架走到不同的道路上实现两开花。

Vue进行数据拦截/代理,使得vue对数据的变化更敏感,更精确。也对前端后续框架提供了思路(hooks,function based API)。

React更推崇函数式,它直接进行局部刷新,(ps:传统diff算法时间复杂度为O(n^3),而react理论上是O(n),这个后期会出文章分析。)但是react不知道什么时候去刷新,所以暴漏出setState的api让开发者调用,为了更好的性能又暴漏给开发者shouldComponentUpdate这个生命周期来避免不需要的重新渲染。而react为了避免不必要的更新,对setState默认采用异步更新。(挖坑2)这种设计,给开发者带来了额外的心智负担

这个设计也影响了hooks的实现和表现#

React hooks底层是基于链表(Array)实现的,每次组件render时都会执行所有hooks,因为基于链表,每个hook的next指针是指向下一个hook的,所以要求开发者不能再hook中进行逻辑判断(if),因为if会使hook执行顺序不正确,导致报错。

vue hook 只会在注册时调用一次,vue会避免上述问题主要还是因为响应式方案,但是vue也有问题困扰。比如useState(),返回的是一个value wrapper(包装对象),包装对象只有一个属性value,指向内部被包装的值。我们都知道,在js中string和number是只有一个值的,是没有引用的,不管是使用Object.defineProperty 还是 Proxy,都无法追踪原始值后续的变化,所以vue才会返回一个包装对象,不这样的话,vue就无法对基本数据类型进行代理和拦截。这也算是vue设计理念带来的副作用了。

Mobx采用响应式思想,在react社区很流行,Mobx + react的组合也可以被看作更繁琐的Vue。

2.设计哲学#

React事件系统庞大且复杂,其中,它暴漏给开发者的事件不是原生事件,是 React 包装过合成事件,并且非常重要的一点是,合成事件是池化的。也就是说不同的事件,可能会共享一个合成事件对象。另外一个细节是,React 对所有事件都进行了代理,将所有事件都绑定 document 上。

另外,React 中事件处理函数中的 this 默认不指向组件实例。

当然 Vue 事件处理函数中的 this 默认指向组件实例。

从事件 API 上我们就能看出前端框架在设计的一个不同思路: React 设计是改变开发者,提供强大而复杂的机制,开发者按照我的来;Vue 是适应开发者,让开发者怎么爽怎么来。

3.预编译优化问题#

Vue core 可以静态分析 template,在解析模版时,整个 parse 的过程是利用正则表达式顺序解析模板,当解析到开始标签、闭合标签、文本的时候都会分别执行对应的回调函数,来达到构造 AST 树的目的。

React拥有的是一堆递归 React.createElement 的执行调用,所以React JSX 过度的灵活性导致运行时可以用于优化的信息不足,除了fiber的时间分片还可以通过工程化手段达到类似的目的,类似于React与Prepack的合作。

引用尤大在知乎回复#

这个问题下面的很多回答太偏激了,其实我淡出知乎就是因为这类破事... 但是作为作者还是认真地说一说吧,希望能以后别再有这种问题了。

这里我可以大方地承认,如果多年以后要论历史地位,React 肯定是高于 Vue 的。事实上,我作为一个开发者,也是由衷地佩服 Jordan Walke, Sebastian Markbage 这样的,能从开发模式层面上提出突破性的新方向的人。

React 从一开始的定位就是提出 UI 开发的新思路。当年 Pete Hunt 最开始推广 React 的时候的一句口号就叫 "Rethinking Best Practices",这样的定位使得 React 打开了一些全新的思路,吸引了一群喜欢折腾的早期核心用户,并在这个基础上通过社区迭代孵化出了许多今天被 React 开发者当作常识的 pattern。这是 React 伟大的地方,Vue 里面也有很多地方是直接受到了 React 的启发。React 敢做这样的尝试,是因为它是 Facebook。这样的体量的公司,在 infrastructure 层面获得质的提升,收益是巨大的,而且 Facebook 的工程师们足够聪明又要靠工资吃饭,改变他/她们的习惯并不是什么问题。而对外推广,则是一种大公司才有的 “改变业界” 的底气。

Vue 从一开始的定位就是尽可能的降低前端开发的门槛,让更多的人能够更快地上手开发。我以前也说过,开发 Vue 的初衷不是为了搞个大新闻,只是做了个我自己用得舒服的框架。我虽然也在 Google 这样的大公司呆过,但骨子里是一个喜欢自由的人,也一直觉得独立开发者很酷(这也是为什么最终自己也成了一个独立开发者)。很多时候我更希望自己做的东西能帮到那些中小型企业和个人开发者。举个例子来说,美国传统行业里有很多 small business,它们不像大公司那样有专门的 IT 团队来信息化整个流程,很多只能雇一个普通的 contractor 程序员,有些甚至是老板自己兼职研究代码。我收到过好几封这样的感谢信,说因为 Vue 让它们多快好省地做了个内部应用,解决了实际问题,这样的故事是让我觉得特别爽的。

做 React 这样的不迎合用户,而是试图改变用户的设计需要有足够的本钱:你得有足够的资源和背景去强行越过初始推广的那个陡坡。事实上,如果没有 Facebook 作为 React 的推广者,React 很可能最终是一个有着忠实用户群体的小众框架(比如 Elm)。作为一个个人项目的 Vue 没有这样的宣传资源,也并不是为了改变用户。所以从设计的角度上来说,Vue 首先考虑的是假设用户只掌握了 web 基础知识 (HTML, CSS, JS) 的情况下,如何能够最快理解和上手,实现一个看得见摸得着的应用。

一个 API 看得顺不顺眼,用得舒不舒服,很大程度上取决于你跟一个技术的核心用户群体的重合程度。编程语言之间喷来喷去还少么?大家都是图灵完备,然而此之蜜糖,彼之砒霜。Vue 的 API 设计固然有可以商榷的地方,但 React 也不是完美无瑕,不然也不会从 mixins 到 HOC 到 render props 一次次地折腾,更没有 hooks 什么事了。直到 Suspense 出现前,也不存在什么只有 React 才能做到的事情(顺带一提,有意思的是 hooks 基本上废掉了过去大部分基于组件的逻辑抽象模式,抹掉了 JSX vs. 模版的一个优势,也完全可以用在其他框架里,连 Angular 都已经有对应的原型实现...)然而 “不完美” 并没有妨碍在过去的几年内大量的用户用各自选择的技术做出实际的产品 —— 从 State of JS 近两年的数据来看,两者的满意率是差不多的,都在 90% 出头,说明两者在 “满足目标用户的需求” 这个衡量标准下,表现是差不多的。可维护性、可读性、优雅程度、生态这些东西嘴上怎么辩都可以,还是数据比较实在。

再说说具体技术层面:从加载速度、运行时性能来说,两者目前综合各种场景应该说是没有什么质的差别。硬要说的话,Vue 在 update 性能优化方面需要的心智负担可能少那么一点 —— React 如果不注意,容易导致过多的组件无用 diff,但是实际上真正会遇到性能瓶颈的应用也是少数... Vue 3 会比 Vue 2 快不少,加上模版编译还有一些可进一步发掘的优化空间,所以性能上会比现在的 React 有一定优势,但 React 那边也在研究基于 prepack 的编译时优化,这个也是挺值得期待的。Vue 3 对于 TS 的支持会有很大改善(包括 TSX),我们也在计划对模版做更好的 IDE 支持(比如补全、类型检查),现在没有不代表以后不能有,有批评我们改进就是了。其实过去大半年 Vue 本身没有什么大更新是因为精力都放在工具链上了,接下来又要回到核心上了。React 那边 time slicing / Concurrent mode 要明年 Q2 才稳定,那个时候应该 Vue 3 的 time slicing 应该也稳定了(原型已实现)。Suspense 在 data-fetching 稳定之前并没什么大用(要 2019 年中),这期间我们也会研究解决同类问题的方案。所以从纯技术层面来说,React 现在比 Vue 牛逼么?不好说。以后一定比 Vue 牛逼么?也不好说。

使用数量方面,有很多文章拿各种数据来比较,有的是 GitHub stars,有的是 npm 下载量,有的是 Google trends,有的是 StackOverflow 的问题数量... 其实这些数据都有很明显的问题,那就是它们跟实际使用者的数量并不一定是正比,会受到其它因素的影响,比如 GitHub stars 跟实际使用没有直接关联;使用者中使用 CI 的比例会影响 npm 的下载量;Google trends 很难完美过滤掉 React 这样的常见词汇的 false positive;文档和本身的上手难易程度会影响 StackOverflow 的问题数量,等等... 所以我自己一直是以 Chrome 开发者插件的使用者数量作为一个比较可靠的数据,因为它的关联度是最直接的,潜在的干扰因素也是最少的。目前 Vue 的开发者插件用户数量约为 70.4 万,而 React 是 136.3 万,大致可以作为参考。React 的使用量还是有明显优势,不过这个数字比起两年前已经很不一样了 —— 那时候大约是 1:7 的比例。从增速来看,Vue 是要快一些的。

说了这么多,无非是希望大家能停下来想想所谓的 ”A 技术比 B 技术牛逼“ 背后到底是在争些什么,我们使用这些技术的初衷又是什么。很多时候你说这方面,他说那方面,鸡同鸭讲,即使说到一起去,也往往缺乏对等的信息量或者基础共识,只是各自表达主观看法,最后变成两个阵营各自抱团取暖... 说到底,就算你证明了 A 比 B 牛逼,也不意味着你或者你的项目就牛逼了... 比起争这个,不如多想想怎么让自己变得更牛逼吧。

--2018-12-04

结尾#

各有千秋,正是因为思想开花,前端才会如此蓬勃发展,未来可期。交流♂要文明,不要人身攻击 :>