You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
16 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 01 | 宏观视角从前端框架发展史聊聊为什么要学Vue 3
你好,我是大圣。
今天,我们来聊一聊前端框架的发展历史。在熟悉这段历史之后,相信你能把握到 Vue 在前端框架中的地位。这样,你就会对 Vue 有一个更精准的定位,从而能够知道我们为什么要选择 Vue 框架以及Vue的优势和它的真正价值在哪里。
同时,前端框架的发展历史可能也会让你感触很多。因为每一个上网的人,或多或少都会感觉到前端网页在这些年发生了很多的变化,这是一种切身的、直观的体会。我们都能感觉到网页在设计模式、渲染等等地方的变化,而这种种变化的背后,其实都可以放到前端框架的演变历史中来解释。
## 石器时代
谈前端框架发展史之前,我们先来简单回顾一下前端的发展历史吧。
* 1990 年,第一个 Web 浏览器诞生了。这是前端这个技术的起点,代表这一年它出生了。后面的时间里,前端圈有很多里程碑事件。
* 1994 年,网景公司发布第一个商业浏览器 Navigator。
* 1995 年,网景工程师 Brendan Eich 用 10 天时间设计了 JavaScript同年微软发布了 IE 浏览器,进而掀起了浏览器大战。
* 2002年IE在浏览器大战中赢得胜利IE6占有率超过96% 。
而前端的发展历史又非常直观地显示在你看到的前端网页的演变历史中。整个90年代受限于网速网页都是静态页显示非常单一前端的工作大部分都只是让美工来切切图和写写HTML+CSS。也因此在90年代前端还处在一种萌发期的状态前端工程师这一工种也没有明确出现。
再后来后端越来越复杂开始分层。就像在小公司里大家啥都干但公司规模大了之后就要分部门职责明确代码也从揉在一起发展到ModelView和Controller分别负责不同的功能。
**这就是后端MVC模式的盛行让我们可以在模板里写上要展现的数据。以前的代码都是所有内容写在一起现在就会用Model负责数据。**
后端渲染页面之前会把数据库的数据显示在前端。这个时候除了写前端代码必备的HTML、CSS和简单的JavaScript动效我们也开始用到了JSP和Smarty我们会写出如下这种代码
```xml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>smarty test1</title>
</head>
<body>
它的名字叫{$name}
</body>
</html>
```
上述代码写出来的页面,就可以直接显示后端数据库里的数据了,这也就是所谓的动态网页。动态页面使得前端本身的丰富程度大大提升。这一下子迎来了整个互联网开发的繁荣时期,但这种模式下的任何数据更新,都需要刷新整个页面,并且在带宽不足的年代,这样做会耗费不少加载网页的时间。
所以这个时代的网页主要还是以显示数据和简单的特效为主,比如当时众多的门户网站,也都没有太多的用户交互,主要就是显示后端存储的新闻。
直到2004年Google发布了Gmail用户可以在不刷新页面的情况下进行复杂的交互之后Ajax逐渐成为网页开发的技术标准也不断地被应用于各种网站。**Ajax这个技术让我们可以异步的获取数据并且刷新页面从此前端不再受限于后端的模板这也宣告了Web2.0时代正式到来。**至此,前端工程师也正式作为一个独立工种出现。
## 铁器时代
在Gmail诞生后虽然依然有浏览器的混战和兼容性问题比如绑定事件不同的浏览器就要写不同的代码但大家意识到前端也可以做出复杂应用。而jQuery的出现迅速风靡全球一个$走天下学会jQuery就等同于学会了前端算是前端车同轴的时代。在这之后前端的具体开发不再被JavaScript的兼容性问题所困扰。
那个时候 jQuery+Bootstrap一把梭成为了前端开发领域的主流技术前端代码内嵌在后端的项目中写完直接发布通篇都是如下的代码
```xml
$('#alert-btn').on('click',function(){
$('#app .input').val('hi')
})
```
那个时候写代码就是找到某个元素进行DOM操作特别像铁器时代的拼刺刀随着前端项目规模的逐渐提升前端也需要规模化的时候在2009年AngularJS和Node.js的诞生也宣告前端工业革命的到来。
## 工业时代
AngularJS的诞生引领了前端MVVM模式的潮流Node.js的诞生让前端有了入侵后端的能力也加速了前端工程化的诞生。现在前端三大框架Angular、React、Vue 的发展主线,也就是从这里开始的。
所谓MVVM就是在前端的场景下把Controller变成了View-Model层作为Model和View的桥梁Model数据层和View视图层交给View-Model来同步第二讲我们会通过一个清单应用让你熟悉MVVM开发模式和传统jQuery的开发模式的区别这里你先留个印象就好。
### 前端三大框架
在前端MVVM模式下不同框架的目标都是一致的就是利用数据驱动页面但是怎么处理数据的变化各个框架走出了不同的路线。
![](https://static001.geekbang.org/resource/image/b0/93/b0402b9e1b4cb22877fcffb8b43d0193.jpg?wh=1208x678)
这些框架要回答的核心问题就是,数据发生变化后,我们怎么去通知页面更新。各大框架在这个步骤上,各显神通:
Angular 1就是最老套的脏检查。所谓的脏检查指的是Angular 1在对数据变化的检查上遵循每次用户交互时都检查一次数据是否变化有变化就去更新DOM这一方法。这个方法看似简单粗暴但算是数据驱动页面早期的实现所以一经推出就迅速占领了MVVM市场。
后面Angular团队自断双臂完全抛弃Angular 1搞了一个全新的框架还叫Angular引入了TypeScript、RxJS等新内容虽然这些设计很优秀但是不支持向前兼容抛弃了老用户。这样做也伤了一大批Angular 1用户的心包括我。这也是Angular这个优秀的框架现在在国内没有大面积推广的原因。
而Vue 1的解决方案就是使用响应式初始化的时候Watcher监听了数据的每个属性这样数据发生变化的时候我们就能精确地知道数据的哪个key变了去针对性修改对应的DOM即可这一过程可以按如下方式解构
![](https://static001.geekbang.org/resource/image/c8/0b/c8f234a40e63dbf86809f6885714b10b.jpg?wh=2540x1441)
在上图中,左边是实际的网页内容,我们在网页中使用{{}}渲染一个变量Vue 1就会在内容里保存一个监听器监控这个变量我们称之为Watcher数据有变化watcher会收到通知去更新网页。
通俗来说,如果把网页数据看成你管理的员工,普通数据就是那种每次你都需要找到他,告诉他要怎么做的人,响应式数据就是他本身有任何变化,都会主动给你发日报告诉你的积极员工。
此外Facebook的React团队提出了不同于上面的Angular、Vue的的解决方案他们设计了React框架在页面初始化的时候在浏览器DOM之上搞了一个叫虚拟DOM的东西也就是用一个JavaScript对象来描述整个DOM树。我们可以很方便的通过虚拟DOM计算出变化的数据去进行精确的修改。
我们先看React中的一段代码
```xml
<div id = "app">
<p class = "item">Item1</p>
<div class = "item">Item2</div>
</div>
```
在React中这样一段HTML会被映射成一个JavaScript的对象进行描述。这个对象就像数据和实际DOM的一个缓存层通过管理这个对象的变化来减少对实际DOM的操作。
这种形式不仅让性能有个很好的保障我们还多了一个用JSON来描述网页的工具并且让虚拟DOM这个技术脱离了Web的限制。因为积累了这么多优势虚拟DOM在小程序客户端等跨端领域大放异彩。
虚拟DOM在运行的时候就是这么一个对象
```xml
{
tag: "div",
attrs: {
id: "app"
},
children: [
{
tag: "p",
attrs: { className: "item" },
children: ["Item1"]
},
{
tag: "div",
attrs: { className: "item" },
children: ["Item2"]
}
]
}
```
这个对象完整地描述了DOM的树形结构这样数据有变化的时候我们生成一份新的虚拟DOM数据然后再对之前的虚拟DOM进行计算算出需要修改的DOM再去页面进行操作。
浏览器操作DOM一直都是性能杀手而虚拟DOM的Diff的逻辑又能够确保尽可能少的操作DOM这也是虚拟DOM驱动的框架性能一直比较优秀的原因之一。
![](https://static001.geekbang.org/resource/image/b2/b4/b262c52d5c353008715003fa263403b4.jpg?wh=1970x1445)
### Vue 与 React 框架的对比
通过上面对前端三大框架的介绍,我们不难发现 Vue 和 React 在数据发生变化后,在通知页面更新的方式上有明显的不同,通俗的来说,就是:**在 Vue 框架下如果数据变了那框架会主动告诉你修改了哪些数据而React的数据变化后我们只能通过新老数据的计算 Diff来得知数据的变化**。
这两个解决方案都解决了数据变化后,如何通知页面更新的问题,并且迅速地获得了很高的占有率,但是他们都碰到了性能的瓶颈:
* 对于 Vue 来说它的一个核心就是“响应式”也就是数据变化后会主动通知我们。响应式数据新建Watcher监听本身就比较损耗性能项目大了之后每个数据都有一个watcher会影响性能。
* 对于React的虚拟DOM的Diff计算逻辑来说如果虚拟DOM树过于庞大使得计算时间大于16.6ms,那么就可能会造成性能的卡顿。
为了解决这种性能瓶颈, Vue 和 React 走了不同的道路。
React为了突破性能瓶颈借鉴了操作系统时间分片的概念引入了Fiber架构。通俗来说就是把整个虚拟DOM树微观化变成链表然后我们利用浏览器的空闲时间计算Diff。一旦浏览器有需求我们可以把没计算完的任务放在一旁把主进程控制权还给浏览器等待浏览器下次空闲。
这种架构虽然没有减少运算量,但是巧妙地利用空闲实现计算,解决了卡顿的问题。你可以看一下我画的图解:
![](https://static001.geekbang.org/resource/image/27/23/27dbe22e81ccc1cec8b35b4ee0a06f23.jpg?wh=2796x1564)
在上图中左侧是一个树形结构树形结构的Diff很难中断右侧是把树形结构改造成了链表遍历严格地按照子元素->兄弟元素->父元素的逻辑随时可以中断和恢复Diff 的计算过程。
为了方便你对计算Diff的理解我们来看下面这张图
![](https://static001.geekbang.org/resource/image/22/6f/22b7606230e2920584387249a83db36f.jpg?wh=2358x806)
这个图里两个虚线之间是浏览器的一帧高性能的动画要求是60fps也就是1秒要渲染60次每一帧的时间就是16.6毫秒在这16.6毫秒里浏览器自己的渲染更新任务执行后会有一部分的空闲时间这段时间我们就用来计算Diff。
等到下一帧任务来了,我们就把控制权还给浏览器,让它继续去更新和渲染,等待空闲时间再继续计算,这样就不会导致卡顿。
Vue 1 的问题在于响应式数据过多,这样会带来内存占用过多的问题。所以 Vue 2 大胆引入虚拟DOM来解决响应式数据过多的问题。
这个解决方案使用虚拟DOM解决了响应式数据过多的内存占用问题又良好地规避了React中虚拟DOM的问题 还通过虚拟DOM给 Vue 带来了跨端的能力。看到这个解决方案的时候,我真是一拍大腿,直呼“真牛!”。
**响应式数据是主动推送变化虚拟DOM是被动计算数据的Diff一个推一个拉它们看起来是两个方向的技术但被 Vue 2 很好地融合在一起,采用的方式就是组件级别的划分。**
对于 Vue 2 来说组件之间的变化可以通过响应式来通知更新。组件内部的数据变化则通过虚拟DOM去更新页面。这样就把响应式的监听器控制在了组件级别而虚拟DOM的量级也控制在了组件的大小。
这个方案也体现了 Vue 一直以来坚持的中庸的设计思想。
下图左边就是一个个的组件组件内部是没有Watcher监听器的而是通过虚拟DOM来更新每个组件对应一个监听器大大减小了监听器的数量。
![](https://static001.geekbang.org/resource/image/22/51/2237975345b4cf039a6cd733cd5be451.jpg?wh=7731x6528)
除了响应式和虚拟DOM这个维度Vue和React还有一些理念和路线的不同在模板的书写上也走出了template和JSX两个路线。
![图片](https://static001.geekbang.org/resource/image/66/0f/669188c294d8e306072ef4273ec2630f.png?wh=1920x635)
React的世界里只有JSX最终JSX都会在Compiler那一层也就是工程化那里编译成JS来执行所以React最终拥有了全部JS的动态性这也导致了React 的API一直很少只有state、hooks、Component几个概念主要都是JavaScript本身的语法和特性。
而 Vue 的世界默认是template也就是语法是限定死的比如v-if 和 v-for等语法。有了这些写法的规矩后我们可以在上线前做很多优化。Vue 3 很优秀的一个点就是在虚拟DOM的静态标记上做到了极致让静态的部分越过虚拟DOM的计算真正做到了按需更新很好的提高了性能。
![](https://static001.geekbang.org/resource/image/64/f9/64e0e2fd877f2d54f4dd97e3dc0b1bf9.png?wh=1334x456)
在模板的书写上,除了 Vue 和 React 走出的template和JSX两个路线还出现了 Svelte 这种框架没有虚拟DOM的库直接把模板编译成原生DOM几乎没有Runtime所有的逻辑都在Compiler层优化算是另外一个极致。
![图片](https://static001.geekbang.org/resource/image/ba/b9/bae38yye39eyy1609260caf90271cbb9.png?wh=1920x759)
## 总结
了解了前端MVVM框架发展的历史和方向后相信你脑海里已经建立起了一个前端框架发展的地图每个框架都在探索自己的路线。后面还会涌现出更多优秀的框架我们到时候只需要把那个框架纳入到这个地图中去理解这样你很快就明白这个框架做了什么而这也是很多前端大神能够快速学习一个新框架的主要原因。
浏览器的诞生让我们可以方便地显示文本和图片的内容和样式JavaScript的出现让网页动了起来Gmail的发布宣告前端也可以使用Ajax异步加载技术来进行复杂网页的开发前端工程师这个工种也正式出现了。
随着浏览器厂商的混战各个浏览器都有自己的特色jQuery框架的出现统一了写法解决了那个时代最棘手的前端问题兼容性极大提高了开发者的效率。
随着Angular 1的诞生我们多了一套开发模式就是数据驱动页面。我们甚至不再需要使用jQuery去寻找DOM而是只关注数据的来源和修改这也就是现在我们所处的前端时代。我们所熟悉的Vue、React、Angular和Svelte等框架都是在数据驱动页面这个场景下涌现的框架。
相信到这里,你已经大概明白前端的这些框架的风格和特点,以及 Vue 在这些框架中的地位Vue 3 在Vue 2 的基础之上做了全面的升级在性能、扩展性和包的大小上Vue3都有质的飞跃。
我已经迫不及待地想聊聊 Vue 3 到底有哪些新特性,并且强烈推荐你来学习。
## 思考题
在你看来Vue需不需要React的Fiber呢
欢迎在留言区分享你的思考,畅所欲言。如果你觉得今天的内容有所帮助,也欢迎你分享给你身边的朋友,邀请他一起学习。