聊聊我对现代前端框架的认知

编者按:本文做者 Berwin,W3C性能工做组成员,360导航高级前端工程师。Vue.js早期用户,《深刻浅出Vue.js》(正在出版)做者。javascript

最近看到一篇国外的文章,说现代JS框架存在的根本缘由是保持UI与状态同步、这其实与我这篇文章的思想是一致的,同时也认证了我对现代前端框架的认知是正确的。前端

如今前端界有三大框架横行,Vue,React,Angular,几乎是全部身为一名前端工程师所必备的一项技能。java

可是我不知道有多少人仔细思考过为何会这样?git

如今的一些应届生和刚入行的人们,在刚一踏入前端这个行业起就会面临着是学习Vue仍是学习React又或者是学习Angular等这样的选择问题。github

事实上在早几年是没有这个问题的,咱们不须要选择,那时候咱们写前端就是jQuery一把梭,就是干,干就完了。前端框架

一把梭

那为何如今人们须要选择各类框架了呢?

其实之因此如今咱们须要选择框架,本质上是由于咱们面临的需求变了。你们确定都明白若是咱们只写一个纯展现信息的页面,没有任何交互功能的页面,其实即使是如今,咱们也是不须要选择框架的,咱们只须要写几行CSS和HTML就能够完成任务。微信

因此是由于咱们面临的需求变得复杂了,咱们的应用常常须要在运行时作一些交互。前端工程师

这里面有三个很重要的字我标了粗体,叫作运行时(Runtime)。现代的前端开发,咱们开发的应用常常须要在运行时来作一些交互,这些交互在早期只是个幻灯片或者Tab切换下拉菜单等一些简单的交互,这些交互用jQuery实现彻底没什么问题。但现代的前端咱们的目标是用Web去PK原生应用,去和Native进行PK。app

那这个时候咱们会发现用jQuery来开发应用,咱们的代码变得很难以维护,那为何使用现代框架好比Vue,React等就变得容易维护了呢?框架

这里面请容我讲一个故事,一个小插曲,前几天我在一个微信群里面有人讨论,Vue和jQuery的区别是什么,有人很是强烈的说什么差异是Vue有组件,有什么这个那个的一些特性。

当时我在微信群里说了个人观点,我说Vue和jQuery之间的区别只有一点,声明式与命令式

咱们能够想一下,咱们用jQuery去操做DOM的目的是什么?是为了局部更新视图,换句话说是为了局部从新渲染

jQuery是命令式的操做DOM,命令式的局部更新视图,而现代主流框架Vue,React,Angular等都是声明式的,声明式的局部更新视图。

为何声明式的操做DOM就可让应用变得好维护了呢?

弄明白这个问题首先咱们先简单介绍下什么是命令式,什么是声明式。

命令式

命令式,像jQuery,咱们都是想干什么而后就去干就完了,例以下面的代码:

$('.box')
  .append('<p>Test</p>')
  .xxx()
  .yyy()
  .jjj()
  ...
复制代码

命令式就是想干什么就直接去调用方法直接干就完了,简单直接粗暴。

试想一个很简单的场景,好比一个toggle效果,点击一个按钮,切换颜色。

用命令式写,咱们确定是这样写,若是当前是什么颜色就让它变成另一个颜色。

若是你仔细思考,其实这里面能够细分红两个行为,一个是对状态判断,另外一个是操做DOM。

那什么是声明式??

声明式

声明式是经过描述状态与视图之间的映射关系,而后经过这样的一个映射关系来操做DOM,或者说具体点是用这样的映射关系来生成一个DOM节点插入到页面去。好比Vue中的模板。模板的做用就用是来描述状态与DOM的映射关系。

一样的场景,咱们用Vue中的模板来实现,当咱们用模板描述了映射关系以后,咱们在点击按钮时,咱们只须要对颜色这个变量进行修改就能够完成需求。

看到区别了么?

仔细思考下,用Vue来实现一样的需求,若是细分来看,咱们在逻辑上只有一个行为,只有状态。而jQuery是两个行为,状态+DOM操做。

因此声明式为何能够简化维护应用代码的复杂度?

由于它让咱们能够把关注点只放在状态的维护上。这样一来当应用复杂后,其实咱们的思惟,咱们管理代码的方式只在状态上,全部的DOM操做都不用关心了,能够说大大下降代码维护的复杂度。

咱们再也不须要关注怎么操做DOM,由于框架会帮咱们自动去作,咱们只关注状态就行了。

可是若是应用特别特别复杂,咱们会发现即使是咱们只关注状态的维护,依然很难,即使只维护状态也很难,因此才出现了Vuex,Redux等技术解决方案。

什么是渲染?

通过前面的介绍,你会发现其实现代主流框架要解决的最本质的问题依然是渲染,只是不一样框架之间的解决方案有差别,那么什么是渲染?

如今开发前端,咱们的应用在运行时须要不断的进行各类交互,现代主流框架让咱们把关注点放在了状态的维护上,也就是说应用在运行时,应用内部的状态会不断的发生变化。

而将状态生成DOM插入到页面展现在用户界面上,这一套流程叫作渲染。

现代前端框架对渲染的处理

当应用在运行时,内部状态会不断的发生变化,这时用户页面的某个局部区域须要不停的从新渲染。

如何从新渲染?

最简单粗暴的解决方式,也是我平时在没有使用任何框架的项目里写的一些简单的功能时最经常使用的方式是用状态生成一份新的DOM,而后用innerHTML把旧DOM替换了。

我写的小功能块用这种方式没问题,由于功能涉及到的DOM标签少,状态变的时候,几乎就是我这个功能块的全部标签都须要变,因此即使是用innerHTML也不会有太大的性能浪费,是在可接受范围内的。

可是框架不行,框架若是用innerHTML这样去替换,那就不是局部从新渲染了,而是整个页面总体刷新,这性质就变了,那么框架如何作到局部从新渲染?

解决这个问题,须要一些技术方案来解决,能够是VirtualDOM,但并不必定必须是VirtualDOM,也能够是Angular中的脏检测的流程,也能够是细粒度的绑定,像Vue1.0就是使用细粒度的绑定来实现的。

什么是细粒度绑定?

细粒度的绑定意思是说,当某个状态,与之绑定的是页面中的某个具体的标签。就是说,若是模板中有十个标签使用了某个变量,那么与这个变量所绑定的就是10个具体的标签。

相对比较React和Angular粒度都比较粗,他们的变化侦测其实不知道具体哪一个状态变量,因此须要一个暴力的比对,比对后才知道须要对视图中的哪一个部分进行更新。

而Vue这种细粒度的绑定其实在状态发生变化的那一个瞬间,马上就知道哪一个状态变了,并且还知道有哪些具体的标签使用了这个状态,那么事情就变的简单的多了,直接把与这个状态所绑定的这些具体的标签进行更新就能达到局部更新的目的。

可是这样作其实也有必定的代价,由于粒度太细,会有必定的依赖追踪的开销。因此Vue2.0开始采起了一个折中的方案,就是把绑定调整为中等粒度。

一个状态对应某个组件,而再也不是具体标签,这样作有一个好处是能够大大下降依赖的数量,毕竟组件的数量与DOM中的具体标签比,数量要少的多。可是这样就须要多一个操做,当状态发生变化只通知到组件,那么组件内部如何知道具体更新哪一个DOM标签??

答案是VirtualDOM。

也就是说,当粒度调整为中等以后,须要多一个操做就是在组件内部使用VirtualDOM去从新渲染。

Vue很聪明地经过变化侦测+VirtualDOM这两种技术方案,提高了框架运行的性能问题。

因此说,Vue2.0引入VirtualDOM并非由于VirtualDOM有多好,而是刚好VirtualDOM结合变化侦测能够将绑定调整成中等粒度来解决依赖追踪的开销问题。

关于变化侦测我专门写过文章来介绍Vue是如何实现变化侦测的。传送门

因此变化侦测的方式,在必定程度上就已经决定了框架如何进行渲染。

关于VirtualDOM的实现原理我写过一个PPT,有兴趣的能够看看,传送门

还有一个是模板编译,其实前面对于模板编译这个问题并无说太多,模板的做用是描述状态与DOM之间的映射关系,经过模板能够编译出一个渲染函数,执行这个渲染函数能够获得VirtualDOM中所提供的VNode,事实上你看过我前面介绍VirtualDOM原理的PPT你就会知道VirtualDOM对节点进行diff实际上是对VNode进行diff。关于模板编译的实现原理我专门写过一篇文章介绍过,传送门

最后

最后我想说的话是,如今的前端我我的感受有点浮躁,不少人都在追新,天天关注一些今天出了一个新特性,明天出了一个新框架什么的,对于这些我是同意的,可是我更但愿在追新的同时,要看到它的本质。

全部技术解决方案的终极目标都是在解决问题,都是先有问题,而后在有解决方案,解决方案可能并不完美,可能解决方案有不少种,那么他们之间都有哪些优缺点?解决问题的同时各自都作了哪些权衡和取舍?

咱们要透过现象看本质才不至于被表面所迷惑。

关于奇舞周刊

《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送连接到后台便可给咱们投稿。

奇舞周刊
相关文章
相关标签/搜索