这一部分介绍单页应用框架所依赖的基础技术和原理。经过这一部分的学习,你应该可以了解到一个单页应用,或者说一个单页应用框架是如何运作的。掌握一个单页应用各个组成部分,在平时开发时可以更好地甄别框架和组件,游刃有余地进行开发。
单页应用的出现不可考。从 Wikipedia 上可以看到,起源很早,甚至可以追溯到2002年。你可能会说,这不是什么新概念,Google 的 Gmail 就是一个单页应用,可追溯到2004年到2005年。但这个概念火热起来在2010年,Backbone 问世之后。随着后来的 Knockout、Ember.js、AngularJS 的兴起,单页应用开始家喻户晓起来。2015年 React 的出现,Virtual DOM 横扫了各种 MV* 框架,单页应用框架甚至进入到了一个新的时代,甚至与函数式编程结合到了一起。比如 Angular 2 与 RxJS 的结合,React 与 Redux 的结合等等。
为了说清楚什么是单页应用,我们先来看看传统的网页应用是什么样子的。
{% mermaid %} sequenceDiagram 浏览器->>服务器:刷新、超链接、表单提交 服务器-->>浏览器:HTML 页面 {% endmermaid %}
目前绝大部分的网站都还采用这种形式。单个 HTML 页面作为功能元件,通过刷新,超链接、表单提交等方式,组合排列这些 HTML 页面,来为用户提供服务。作为网页应用的传统形式长久不衰,很多流行的开发框架都以之作为范式设计的。比如 Ruby on Rails,Spring MVC,Express 等等。
{% mermaid %} graph LR subgraph 服务端 控制器((控制器)) --> 视图((视图)) 控制器((控制器)) --> 数据服务((数据服务)) 数据服务((数据服务)) -.-> 视图((视图)) end subgraph 浏览器 前端展示((前端展示)) --> 控制器((控制器)) 视图((视图)) -.-> 前端展示((前端展示)) end {% endmermaid %}
在传统的网页应用中,浏览器更多的是充当一个展示层,路由处理、服务调用、页面跳转流程都由服务端来处理。即 MVC 都放在服务器端,而 V 作为用户界面则通过网络发送到浏览器端,作为 UI 与用户交互。
这样的范式有以下特点:
- 重服务端,由于 MVC 都存在于服务器上,因此这类应用在开发资源和开发的重心都偏向后端,往往是后端工程师来主导整个项目开发;
- 页面频繁刷新,由于浏览器端只是一个展现层,当页面功能有所变化的时,页面就刷新,这会导致资源的浪费,用户需要花费额外的时间等待页面刷新,用户体验不佳。
当然,上面表达的是一种普遍的范式,而 Ajax 则是这个范式的异类。Ajax 的出现使得网页可以局部更新,使得网页上的一部分可以作为一个功能元件来为用户提供服务。这种形式的网页应用已经具备单页应用的雏型,但并不是标准的单页应用。
相较于传统网页应用,单页应用将 MVC 前置到了浏览器端:
{% mermaid %} graph LR subgraph 浏览器 控制器((控制器)) --> 视图((视图)) 视图((视图)) --> 数据层((数据层)) end subgraph 服务端 数据层((数据层)) -.-> 数据服务((数据服务)) end {% endmermaid %}
- 控制器前置,单页应用将路由处理放在浏览器端,即在浏览器端直接响应浏览器地址的变化,分发到对应的路由,向用户呈现对应的界面。
- 以小块组件为功能元件,类似于传统网页中的 Ajax 组件,单页应用以小的组件为功能元件,在路由变化时,不再刷新整个页面,而是组合这些小的组件,替换变化的部分。
- 数据层前置,与 Ajax 组件一个明显的区别是,单页应用在浏览器端通常有一层实实在在的数据层,而服务端则退化成了完全的数据 API。浏览器端的数据层会封装服务端 API,供上层的视图层调用。
看上去有点类似于客户端(Android、iOS)开发,交互全都放在客户端,服务端仅仅提供 API。
每种技术都有其利弊,单页应用也是如此。我们先说说好的地方:
- 无刷新体验,这个应该是最显著的有点,由于路由分发直接在浏览器端完成,页面是不刷新,对用户的响应非常及时,因此提升了用户体验;
- 完全的前端组件化,前端开发不再以页面为单位,更多地采用组件化的思想,代码结构和组织方式更加规范化,便于修改和调整;
- API 共享,如果你的服务是多端的(浏览器端、Android、iOS、微信等),单页应用的模式便于你在多个端共用 API,可以显著减少服务端的工作量。容易变化的 UI 部分都已经前置到了多端,只受到业务数据模型影响的 API,更容易稳定下来,便于提供鲁棒的服务;
- 组件共享,在某些对性能体验要求不高的场景,或者产品处于快速试错阶段,借助于一些技术(Hybrid、React Native),可以在多端共享组件,便于产品的快速迭代,节约资源。
单页应用的优点有时候也是缺点:
- 首次加载大量资源,要在一个页面上为用户提供产品的所有功能,在这个页面加载的时候,首先要加载大量的静态资源,这个加载时间相对比较长;
- 较高的前端开发门槛,MVC 前置,对前端工程师的要求提高了,不再是『切切图,画画页面这么简单』;同时工作量也会增加数倍,开发这类应用前端工程师的数量往往多于后端;
- 不利于 SEO,单页页面,数据在前端渲染,就意味着没有 SEO,或者需要使用变通的方案。
在笔者看来,单页应用是对原来 Ajax 组件的一种延伸,相较于传统的网页应用,将 MVC 前置到了浏览器端,浏览器就相当于 iOS 系统,单页应用就像是应用,与服务端仅仅通过 API 来沟通。每种技术方案都有利弊,是否要使用单页应用技术,需要通过对产品需求(跨平台、SEO、性能、用户群属性?)、资源(工程师配比,能力?)时间要求等的评估来做出选择。
接下来,我们先从单页应用的视图开始学习,看看前端工程师最熟悉的组件,在单页应用中是什么样子的!