摘要:从angular的诞生独步天下,到现在三大框架平分天下,基本形势已经趋于稳定。每一个框架从诞生到受欢迎,都有其特定的原因和背景。不同的开发者选择时,也是依据于其特定情景下的原因和背景。
一、为什么前端会被vue,angular,react瓜分?
不知道大家有没有发现,这三个框架除了都是前端框架之外,还大有搞基的成分存在。注意他们三个的名字,分别以v,a,r 开头,我这么一说,你是不是忽然间就想到了什么。哈哈,正是如此,将他们组合起来不就是java中无处不在的鬼东西么?var (当然纯属于开玩笑的)var关键字,是js的变量声明关键字,可以说,它是js得以运行的核心关键字,因为要想一段代码运行,首先得有各种变量和逻辑判断做支撑,而在es6之前,js能声明变量的,就它一个。这似乎也是暗示了vue,angularjs,react这三个框架的不可替代性啊,也不知道当时这三个框架的作者起名时的想表达的特殊含义是什么,但偏偏就刚好对上了。当然,反过来说,也有可能是起var关键字的这个人,当时考虑得面面俱到。虽然看上去是巧合,但我总感觉这之中总有一种道不明的关系。虽然vue是后起之秀,但就目前的受欢迎程度来说,好像就是这个顺序,至少国内现在肯定是这样的。有了这三个框架之后,我们告别了以前jquery面条式的代码,也摆脱了到处操作dom元素带来的繁琐,模块业务划分更清晰。这三个框架的出现,不仅让前端的工作得以高效,也让后端省了不少事,比如,路由控制。在以前,干后端是对决要比前端高一个档次的,但现在,完全不一样了。如果有一个牛逼的前端,后端差不多只需要会增删改查的基本业务就能完全搞定一个web应用。当然,这里只是针对代码部分,搭建服务器之类的另当别论。
二、三大框架的优缺点
我们主要从数据流、视图渲染、性能与优化、模块化组件化等四个方面来作比较 1、数据流
Angular 使用双向绑定即:界面的操作能实时反映到数据,数据的变更能实时展现到界面。
1.1、它的实现原理:
scope.scope.scope.scope.scope.$watch时只为它传递了一个参数,无论作用域中的什么东西发生了变化,这个函数都会被调用。在ng-model中,这个函数被用来检查模型和视图有没有同步,如果没有同步,它将会使用新值来更新模型数据。
1.2、双向绑定的三个重要方法:
apply()digest()watch()在angularjs双向绑定中,有2个很重要的概念叫做dirty check,digest loop,dirty check(脏检测)是用来检查绑定的scope中的对象的状态的,例如,在js里创建了一个对象,并且把这个对象绑定在scope下,这样这个对象就处于digest loop中,loop通过遍历这些对象来发现他们是否改变,如果改变就会调用相应的处理方法来实现双向绑定Vue 也支持双向绑定,默认为单向绑定,数据从父组件单向传给子组件。在大型应用中使用单向绑定让数据流易于理解。
1.3、脏检测的利弊
和ember.js等技术的getter/setter观测机制相比(优):getter/setter当每次对DOM产生变更,它都要修改DOM树的结构,性能影响大,Angular会把批量操作延时到一次更新,性能相对较好。和Vue相比(劣):Vue.js 有更好的性能,并且非常非常容易优化,因为它不使用脏检查。Angular,当 watcher 越来越多时会变得越来越慢,因为作用域内的每一次变化,所有 watcher 都要重新计算。并且,如果一些 watcher 触发另一个更新,脏检查循环(digest cycle)可能要运行多次。 Angular 用户常常要使用深奥的技术,以解决脏检查循环的问题。有时没有简单的办法来优化有大量 watcher 的作用域。Vue.js 则根本没有这个问题,因为它使用基于依赖追踪的观察系统并且异步列队更新,所有的数据变化都是独立地触发,除非它们之间有明确的依赖关系。唯一需要做的优化是在 v-for 上使用 track-by。React-单向数据流MVVM流的Angular和Vue,都是通过类似模板的语法,描述界面状态与数据的绑定关系,然后通过内部转换,把这个结构建立起来,当界面发生变化的时候,按照配置规则去更新相应的数据,然后,再根据配置好的规则去,从数据更新界面状态。React推崇的是函数式编程和单向数据流:给定原始界面(或数据),施加一个变化,就能推导出另外一个状态(界面或者数据的更新)。React和Vue都可以配合Redux来管理状态数据。
2、视图渲染 Angular1
AngularJS的工作原理是:HTML模板将会被浏览器解析到DOM中, DOM结构成为AngularJS编译器的输入。AngularJS将会遍历DOM模板, 来生成相应的NG指令,所有的指令都负责针对view(即HTML中的ng-model)来设置数据绑定。因此, NG框架是在DOM加载完成之后, 才开始起作用的。
React
React 的渲染建立在 Virtual DOM 上——一种在内存中描述 DOM 树状态的数据结构。当状态发生变化时,React 重新渲染 Virtual DOM,比较计算之后给真实 DOM 打补丁。Virtual DOM:提供了函数式的方法描述视图,它不使用数据观察机制,每次更新都会重新渲染整个应用,因此从定义上保证了视图与数据的同步。它也开辟了 Java 同构应用的可能性。在超大量数据的首屏渲染速度上,React 有一定优势,因为Vue 的渲染机制启动时候要做的工作比较多,而且React 支持服务端渲染。React 的Virtual DOM 也需要优化。复杂的应用里可以选择 1. 手动添加shouldComponentUpdate 来避免不需要的 vdom re-render;2. Components 尽可能都用 pureRenderMixin,然后采用 Flux 结构 + Immutable.js。其实也不是那么简单的。相比之下,Vue由于采用依赖追踪,默认就是优化状态:动了多少数据,就触发多少更新,不多也不少。React 和 Angular 2 都有服务端渲染和原生渲染的功能。Vue.js不使用 Virtual DOM 而是使用真实 DOM 作为模板,数据绑定到真实节点。Vue.js 的应用环境必须提供 DOM。Vue.js 有时性能会比 React 好,而且几乎不用手工优化。
3、性能与优化
性能方面,这几个主流框架都应该可以轻松应付大部分常见场景的性能需求,区别在于可优化性和优化对于开发体验的影响。Vue 的话需要加好 track-by 。React 需要 shouldComponentUpdate 或者全面 Immutable,Angular 2 需要手动指定 change detection strategy。从整体趋势上来说,浏览器和手机还会越变越快,框架本身的渲染性能在整个前端性能优化体系中,会渐渐淡化,更多的优化点还是在构建方式、缓存、图片加载、网络链路、HTTP/2 等方面
4、模块化与组件 Angular1 -> Angular2
Angular1使用依赖注入来解决模块之间的依赖问题,模块几乎都依赖于注入容器以及其他相关功能。不是异步加载的,根据依赖列出第一次加载所需的所有依赖。可以配合类似于Require.js来实现异步加载,懒加载(按需加载)则是借助于 ocLazyLoad 方式的解决方案,但是理想情况下应该是本地框架会更易懂。Angular2使用ES6的module来定义模块,也考虑了动态加载的需求。
Vue
Vue中指令和组件分得更清晰。指令只封装 DOM 操作,而组件代表一个自给自足的独立单元 —— 有自己的视图和数据逻辑。在 Angular1 中两者有不少相混的地方
React
一个 React 应用就是构建在 React 组件之上的。组件有两个核心概念:props,state。 一个组件就是通过这两个属性的值在 render 方法里面生成这个组件对应的 HTML 结构。传统的 MVC 是将模板放在其他地方,比如 标签或者模板文件,再在 JS 中通过某种手段引用模板。按这种思路,想想多少次我们面对四处分散的模板片段不知所措?纠结模板引擎,纠结模板存放位置,纠结如何引用模板。React 认为组件才是王道,而组件是和模板紧密关联的,组件模板和组件逻辑分离让问题复杂化了。所以就有了 JSX 这种语法,就是为了把 HTML 模板直接嵌入到 JS 代码里面,这样就做到了模板和组件关联,但是 JS 不支持这种包含 HTML 的语法,所以需要通过工具将 JSX 编译输出成 JS 代码才能使用(可以进行跨平台开发的依据,通过不同的解释器解释成不同平台上运行的代码,由此可以有RN和React开发桌面客户端)。
三、我们如何选?
年轻的程序员都是好奇的猫,玩过一个又一个的前端框架。从毛球上弄出一条条的线,玩啊玩,最后这一个个的框架在脑子里搅浆糊。有太多的选择,就是一件麻烦的事;没有选择时,就是一件更麻烦的事;有唯一的选择时,事情就会变得超级简单。当一个程序员学了某个最新的框架之后,通常来说这个框架有着更多的优点,这个时候最容易出现的想法就是替换现有的框架,科室现有的框架并没有什么大的问题,并且评估不充分的时候,新的框架则会有更多的风险。所以最后总结一下:技术选型没有银弹,没有一个框架能够解决所有的问题。这时,为了更好的考量不同的因素,你需要列出重要的象限,如开发效率,团队喜好,开发周期等时机情况选择哪个框架最合适你当前的团队和项目。