berwin/Blog

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

berwin opened this issue · 55 comments

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

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

--------------------------- 我是分割线 2018年6月18 更新,下面是原文 ----------------------

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

但是我不知道有多少人仔细思考过为什么会这样?

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

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

一把梭

那为什么现在人们需要选择各种框架了呢?

其实之所以现在我们需要选择框架,本质上是因为我们面临的需求变了。大家肯定都明白如果我们只写一个纯展示信息的页面,没有任何交互功能的页面,其实即便是现在,我们也是不需要选择框架的,我们只需要写几行CSS和HTML就可以完成任务。

所以是因为我们面临的需求变得复杂了,我们的应用经常需要在运行时做一些交互。

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

那这个时候我们会发现用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。关于模板编译的实现原理我专门写过一篇文章介绍过,传送门

最后

最后我想说的话是,现在的前端我个人感觉有点浮躁,很多人都在追新,每天关注一些今天出了一个新特性,明天出了一个新框架什么的,对于这些我是赞成的,但是我更希望在追新的同时,要看到它的本质。

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

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

博文大佬牛

@Lc2010 哈哈哈哈,老大更牛

@Lc2010 不对,是教导有方,哈哈哈哈哈哈哈

我个人的感受就是面向过程(即针对每个数据变化和视图变化做处理)和数据驱动(关注数据和状态的变化,不关心视图)

@sparkxxxxxx 嗯嗯,对的,你理解的完全正确~

但是数据驱动这个词是抽象词,这是一个非常抽象的高级词汇,这个词下面是一系列的各种技术组合在一起的成果,数据驱动更是一个结果。

而声明式是一个低级词,它有点概念的意思。

但在这篇文章中,意思是差不多的。

@berwin ,哈哈,我是个人感受。因为做过WPF开发所以对MVVM很熟悉,导致现在经常说数据驱动这个词

@sparkxxxxxx 哈哈哈哈哈,你理解的挺对的。

声明式与命令式的区别说得很棒,学习了!那你觉得组件化是不是现代框架和jQuery的一个区别呢?

大神讲的太好了,让我又对VUE有了重新认识

博文大佬牛

@wufenfen 哈哈哈哈,我给你举个例子吧,锤子和斧头,用组件化来和jquery对比,那就好比用锤子的头和斧头的头作对比,它们俩确实头不一样,但我看到的是,锤子是用来锤钉子的,而斧头是用来劈木头的。这才是本质的区别,它们的区别我看到的不是材质和形状,而是作用,用来解决不同的问题。

@alphatr 嘿嘿嘿,盼盼更牛~

赞博文大神

博文大佬牛

@NichoZhang @lijinghust 😂 😂 😂 ,别别别,别这样。哈哈哈哈哈

Vue引入VirtualDOM说到点子上了,楼主果然对框架理解透彻

@huangw1 😂😂 过奖过奖

当时在群里不想撕逼啊,没有意义(那么多活要搞~😂)。 即便jQuery封装良好的,也是可以做数据驱动的。
诚如楼主所说,vue使用了VirtualDOM结合变化侦测实现 中度颗粒追踪,从而实现渲染。即便使用jQuery做类似的事情,反而导致复杂度的上升,针对于开发者来讲,不如直接选择vue等mvvm框架来实现需求。百花齐放的今天,需要深入到库/框架的原理和所解决的问题,根据自身业务和团队能力去选择对应的技术栈,最终的目的解决业务问题,推动公司/自身的成长和发展.

声明跟命令的区分讲的很好,而其他什么vdom,局部渲染,都是为了减少dom成本,因为js的成本比dom成本小太多了,这个是为什么引入vdom 的 key point

@ws456999 怎么说呢,你这么说其实也没什么问题,但是并没有看到本质,还是很浅显的理解。因为即便不引入VirtualDOM,也可以使用js的计算成本来换取DOM的操作成本。这件事的解决方案有很多,并不是只有VirtualDOM可以解决这个问题。

写的清楚

问问大佬,360还有春招么,错过了秋招,很难受。

@ZellerDorjee 关注奇舞周刊,查看历史消息,正在招人

@ZellerDorjee 有春招,关注奇舞周刊查看历史消息就能看到招聘贴啦~

@berwin 我看都是招两年工作经验的社招呀

@ZellerDorjee 应届生也招的,投简历就行~

@jiangtao 哈哈哈哈,为啥你三天前发的评论我今天才看见。

@berwin 不知道呀~

果然是業界大大,的確該看到問題本質,渲染的確改個狀態就好

話說那張圖我好喜歡XDDD,就是給他干~

@syn55698 😂😂😂 不是大大,离大大还远,顶天算小独角兽吧。哈哈哈哈哈哈

看了两篇楼主的文章,服了!

大佬,virtual dom的ppt找不到了

@xunuo0x 好啦~ 哈哈哈,谢谢反馈

Hello,我有一个想法你看看合适不合适,我在浏览大家Github上的blog的时候,发现大家都把文章写到了issues下面,大概是因为可以标记labels的缘故?
然后我看到Github的Wiki是可以同步到本地的,和一个工程的repo没有什么区别。
那么问题来了:可不可以把所有的blog都放到Wiki下面,然后我想看LZ有什么新文章的话,直接pull一下本地就好,我都省了再开网页端了。后续还可以有很多*操作...
不知道LZ觉得这个办法如何呢 ?

@snowshoes wiki的话,留言和评论可能不是那么方便~

@berwin 我看到有很多Repo上的Wiki很不错,然后同步到本地之后,也比较方便查阅
刚才去翻了下Github Issues API,发现可以指定Issues返回的Media Types,这样貌似可以拿到Issues的raw content。不知道大佬怎么看?

@snowshoes 嗯嗯嗯,我考虑考虑看~ 非常感谢给我提了宝贵的建议~😁😁😁

精彩!

mobile 大牛

赞博文

太感谢了!对本新人帮助很大!让我对前端的大局更清楚了,从前完全不知道这些是干嘛的

@SkyJinXX 哈哈哈哈,那太好了。说明我的文章没白写。感谢支持~ 😊😊😊

@chevion 哈哈哈哈,大佬过奖~

@duhongwei @aaawhz 哈哈哈,😝😝感谢支持~

写的很好

component可以讲讲

太棒了

一个Javaweb的开发者,接触的页面都是jsp,thymleaf,freeMark,入手前端的话博主推荐先从哪个框架学起呢?

对前后端分离一直困惑不解,不知道JavaWeb的jsp如何与现在前端三大框架结合才能实现前后端分离呢?

@EvilCodes 其实先学哪个框架都行,至于jsp怎么和框架更好的结合,这个要结合具体案例,不同项目解决方案都不太一样,不好回答 😂😂

博主大大的深入浅出vue.js大概什么时候发售,有点小期待啊

@EvilCodes 这个月底就发售啦。哈哈哈哈

大佬 一再强调注重框架特性 那么问题来了 什么是框架特性?

@yaoyanweb 看下这篇文章~ #26

大佬是真的6.同为95后。我97年,膜拜大佬,向你学习