以下这些内容都是在各个网站、公众号、博客搜集过来的,原文链接太多了就不一一粘贴了,复制谷歌一下应该都可以搜到原文的。图片也是保留了原来作者的水印,可以搜索到原文的。
文章目录
前言
前端术语总结:SSR、物料库、渐进式、函数式、响应式、BFF、微前端、大前端、云端一体化、直出、运行时、编译时等。
一、SSR
1.SSR && CSR
Server-SideRendering(服务端渲染)
服务端渲染则是在服务端完成页面的渲染,在服务端完成页面模板、数据填充、页面渲染,然后将完整的HTML内容返回给到浏览器。由于所有的渲染工作都在服务端完成,因此网站的首屏时间和TTI(页面可交互的时间)都会表现比较好。
但是,渲染需要在服务端完成,并不能很好进行前后端职责分离,而且白屏时间也会比较长,同时,对于服务端的负载要求也会比较高。
而与之对应的是 CSR ,Client Side Rendering(客户端渲染),也就是目前 Web 应用中主流的渲染模式,一般由 Server 端返回的初始 HTML 页面,然后再由 JS 去异步加载数据,然后完成页面的渲染。也就是所有的页面渲染、逻辑处理、页面路由、接口请求均是在浏览器中发生。其实,现代主流的前端框架均是这种渲染方式,这种渲染方式的好处在于实现了前后端架构分离,利于前后端职责分离,并且能够首次渲染迅速有效减少白屏时间。同时,CSR可以通过在打包编译阶段进行预渲染或者骨架屏生成,可以进一步提升首次渲染的用户体验。
但是由于和服务端会有多次交互(获取静态资源、获取数据),同时依赖浏览器进行渲染,在移动设备尤其是低配设备上,首屏时间和完全可交互时间是比较长的。
下面这张图,是同一个应用,用两种不同的方式去渲染,页面的加载时序。(这个是在淘系前端团队的文章里面粘贴过来的。)
(橙色部分为页面背景色,对应了常规意义上的白屏时间)
在内容达到时间上,SSR 工作原理,决定了它的优势,这种差异在弱网环境下会体现的更加明显。
前端使用SSR进行渲染同构有一个非常明显的缺点:服务资源消耗和运维。通常情况下,同构SSR会采用Node服务,需要固定的服务器资源,并且服务器的运维对于前端同学也提出了很高的要求。
- 但当你开始开发一个 SSR 应用时,就已经不在是一个简单的前端开发工程师了,而将被迫成为全栈工程师。交付产物从原来的 JS Bundle 变成了 Node 应用,随之而来的是,需要选型一个 Node 框架,搭建一个 Node 应用,并且应对性能开销、保障应用稳定性等等。
- 其次,还需要考虑如何让现有的前端代码跑到 Server 端上,虽然类似 React 这些主流的框架都提供了 Server 端渲染的能力,但是,不同端上渲染原理和执行环境的差异,会导致编码上的很多差异,比如在 Node 端调用了 window 变量,那么就会报错了,同样的 Hooks 之类的异步更新机制在 Server 端也不适用。
- 最后,当你完成应用的开发,还需要考虑这些问题:如何部署环境、如何负载均衡、如何应对服务器宕机、如何应对用户请求峰值等等
SSR和CSR不同阶段优劣对比:
前后端的渲染本质是一样的,都是字符串的拼接,将数据渲染进一些固定格式的html代码中形成最终的html展示在用户页面上。 因为字符串的拼接必然会损耗一些性能资源。
如果在服务器端渲染,那么消耗的就是server端的性能。
如果是在客户端渲染,常见的手段,比如是直接生成DOM插入到html 中,或者是使用一些前端的模板引擎等。他们初次渲染的原理大多是将原html中的数据标记(例如{{text}})替换。
1.1 SSR优点
- 首屏渲染快、利于SEO、可以生成缓存片段,生成静态化文件、节能(对比客户端渲染的耗电)
1.2 SSR缺点
- 用户体验较差、不容易维护,通常前端改了部分html或者css,后端也需要修改。
- SSR中使用的渲染程序会占用更多的CPU和内存资源
- 一些常用的浏览器的API可能无法正常使用,比如window、document和alert等,如果使用的话需要对运行的环境加以判断。
2.Serverless SSR
Serverless基于触发器调用云端部署的函数,然后调用后端服务。
-
一方面,借助于函数即服务(FaaS)的能力,不需要再去搭建传统的 Node 应用,一个函数就可以变成一个服务,开发者可以更纯粹的关注于业务逻辑。
-
另一方面,FaaS 以函数为单位的形式以及弹性机制,为 SSR 应用带来了天然的隔离性和动态修复能力,可以更好的避免页面间的交叉污染,或一些边界的异常场景对应用带来致命性的伤害。
对于前端同学而言,仅仅只需要实现云端函数的实现,对于服务器的运维管理完全不用关心,同时服务器会实现自动弹性伸缩,有效节省了机器资源。
但Serverless服务器的冷启动目前依旧还是一个非常大的问题:
3.附加
3.1.NSR
UC浏览器在新闻feed流页面加载中采用了NSR(Native Side Rendering),首先在列表页中加载离线页面模板,通过Ajax预加载页面数据,通过Native渲染生成Html数据并且缓存在客户端。
NSR本质是分布式SSR,将服务器的渲染工作放在了一个个独立的移动设备中,实现了页面的预加载,同时又不会增加额外的服务器压力。
3.2 ESR
ESR - Edge Side Rendering,方案的核心思想是,借助边缘计算的能力,将静态内容与动态内容以流式的方式,先后返回给用户。cdn 节点相比于 server,距离用户更近,有着更短的网络延时。在 cdn 节点上,将可缓存的页面静态部分,先快速返回给用户,同时在 cdn 节点上发起动态部分内容请求,并将动态内容在静态部分的响应流后,继续返回给用户。
从上面结果可以看出,在网速越慢的情况下,通过 cdn 流式渲染的最终主要元素出来的时间比原始 SSR 的方式出来得越早。这与实际推论也符合,因为网络越慢,静态资源加载时间越慢,对应的浏览器提前加载静态资源带来的效果也越明显。另外,不管在什么网络情况下,cdn 流式渲染方式的白屏时间要短很多。
二、物料库
这个没找到太确切的资料,不过我的理解是,应该是像Element UI这种成型的组件库,业界已经造好的轮子可以拿来直接使用,提高开发效率的这种。
1.一开始开发时用的Element UI:
2.阿里的飞冰截图:
3.京东的通天塔:(可惜进不去了,还想看看是啥样的)
4.美团的乐高:
搜到一点点关于物料的定义:可按照规范进行标准化构建,并且可以在不同项目,不同团队,不同成员之间复用的任意资源。我们把这类资源统称为物料。
顺便盗了一张关于物料市场的图,大概知道物料库是怎么一回事了,不知道怎么描述,还是看图吧哈哈哈。
参与物料资源生产和消费的对象共有四个:开发者、使用者、设计者、产品/运营。物料资源包括项目的基础框架、组件库、区块和模板。基础框架是项目的样板框架也就是俗称的boilerplate,组件库是基于部门内设计同学提出的Union Design设计规范开发前端组件库。区块可以简单理解为组件的拼装集合,模板就是各种站点的样式模板,其中整合了前面所提到的基础框架+组件库+区块等各种资源。让开发者可以最大限度地减少工作量——代码复用率高,迭代周期短。
三、渐进式
关于渐进式的理解,就想到了Vue,是一个渐进式的框架。
去youtube上看了16年尤大大的发言,找了一下大家对尤雨溪在QCon上海《Vue 2.0——渐进式前端解决方案》的演讲的解释。里面是这么说的:渐进式就是一步一步,不是说你必须一竿子把所有的东西都用上。
Vue从设计角度来讲,虽然能够涵盖这张图上所有的东西,但是你并不需要一上手就把所有东西全用上,因为没有必要。无论从学习角度,还是实际情况,这都是可选的。声明式渲染和组建系统是Vue的核心库所包含内容,而客户端路由、状态管理、构建工具都有专门解决方案。这些解决方案相互独立,你可以在核心的基础上任意选用其他的部件,不一定要全部整合在一起。
这里粘贴一波原文链接
四、函数式
函数式编程关心数据的映射,命令式编程关心解决问题的步骤。
本质上,函数式编程只是范畴论的运算方法,跟数理逻辑、微积分、行列式是同一类东西,都是数学方法,只是碰巧它能用来写程序。
函数式编程有两个最基本的运算:合成和柯里化。
1.函数的合成
如果一个值要经过多个函数,才能变成另外一个值,就可以把所有中间步骤合并成一个函数,这叫做"函数的合成"(compose)。
合成两个函数的简单代码如下:
const compose = function (f, g) {
return function (x) {
return f(g(x));
};
}
函数的合成也必须满足结合律:
compose(f, compose(g, h))
// 等同于
compose(compose(f, g), h)
// 等同于
compose(f, g, h)
2.函数柯里化
函数柯里化,就是把一个多参数的函数,转化为单参数函数。
// 柯里化之前
function add(x, y) {
return x + y;
}
add(1, 2) // 3
// 柯里化之后
function addX(y) {
return function (x) {
return x + y;
};
}
addX(2)(1) // 3
五、响应式
Responsive design,意在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。
1. 响应式界面的四个层次
1、同一页面在不同大小和比例上看起来都应该是舒适的;
2、同一页面在不同分辨率上看起来都应该是合理的;
3、同一页面在不同操作方式(如鼠标和触屏)下,体验应该是统一的;
4、同一页面在不同类型的设备(手机、平板、电脑)上,交互方式应该是符合习惯的。
2. 响应式界面的基本规则
1、可伸缩的内容区块:内容区块的在一定程度上能够自动调整,以确保填满整个页面
2、可自由排布的内容区块:当页面尺寸变动较大时,能够减少/增加排布的列数
3、适应页面尺寸的边距:到页面尺寸发生更大变化时,区块的边距也应该变化
4、能够适应比例变化的图片:对于常见的宽度调整,图片在隐去两侧部分时,依旧保持美观可用
5、能够自动隐藏/部分显示的内容:如在电脑上显示的的大段描述文本,在手机上就只能少量显示或全部隐藏
6、能自动折叠的导航和菜单:展开还是收起,应该根据页面尺寸来判断
7、放弃使用像素作为尺寸单位:用dp尺寸等方法来确保页面在分辨率相差很大的设备上,看起来也能保持一致。
六、BFF
Backends For Frontends:服务于前端的后端
BFF就是服务器设计API时会考虑到不同设备的需求,也就是为不同的设备提供不同的API接口,虽然它们可能是实现相同的功能,但因为不同设备的特殊性,它们对服务端的API访问也各有其特点,需要区别处理。因此出现了类似下图一种设计方式。
以上两张图有相似点,也有不同之处。客户端都不是直接访问服务器的公共接口,而是调用BFF层提供的接口,BFF层再调用基层的公共服务,不同的客户端拥有不同的BFF层,它们定制客户端需要的API。图一和图二的不同之处在于是否需要为相似的设备人,如IOS和android分别提供一个BFF,这个需要根据现实情况决定,不同的项目环境解决手段不一样。
那么采用BFF架构与多端公用、单一的API有什么优点了?最重要的一点是它能够满足因不同客户端特殊的交互引起的对新接口的要求,所以一开始就会针对相应的设备设计好对应的接口。如果使用单一、通用的API,我们一开始并没有考虑到特殊需求,那么有新的请求需要出现时,可能会出现以下问题:
(1)如果添加新的接口,这样容易造成接口的不稳定;
(2)如果考虑在原有的接口上进行修改,可能需要会产生一些的耦合,破坏单一职责。
考虑这样一个简单例子,因为移动APP的屏幕限制,在某一个列表页我们只需要展示一些关键的信息,但是由于调用的是服务端提供统一的API,服务端在设计的时候只考虑到了web端,返回所有的字段信息,但这些对于移动端而言都是无用的。在优化性能时处理这样的问题时,服务器端就需要新增接口或者通过引入相关耦合来解决这样的问题。而使用BFF在很大程度能避免这样的问题。
使用BFF的另一个优点就是当由于某一客户端需要调用调用多个不同的服务端接口来实现某一功能时,可以直接在对应的BFF层编写相应的API,而不会影响到基层的公共服务,且客户端不用直接向多个后台发起调用,可以优化性能。
七、微前端
1、概念优势
概念:微服务是面向服务架构(SOA)的一种变体,把应用程序设计成一系列松耦合的细粒度服务,并通过轻量级的通信协议组织起来具体地,将应用构建成一组小型服务。这些服务都能够独立部署、独立扩展,每个服务都具有稳固的模块边界,甚至允许使用不同的编程语言来编写不同服务,也可以由不同的团队来管理。
即,一种由独立交付的多个前端应用组成整体的架构风格。具体的,将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的小块,而在用户看来仍然是内聚的单个产品。
微前端的理念类似于微服务:将庞大的整体拆成可控的小块,并明确它们之间的依赖关系。
关键优势在于:
1.代码库更小,更内聚、可维护性更高
2.松耦合、自治的团队可扩展性更好
3.渐进地升级、更新甚至重写部分前端功能成为了可能
简单、松耦合的代码库
比起一整块的前端代码库,微前端架构下的代码库倾向于更小/简单、更容易开发
此外,更重要的是避免模块间不合理的隐式耦合造成的复杂度上升。通过界定清晰的应用边界来降低意外耦合的可能性,增加子应用间逻辑耦合的成本,促使开发者明确数据和事件在应用程序中的流向
增量升级
理想的代码自然是模块清晰、依赖明确、易于扩展、便于维护的……然而,实践中出于各式各样的原因:历史项目,祖传代码交付压力,当时求快就近就熟,当时求稳……总存在一些不那么理想的代码:技术栈落后,甚至强行混用多种技术栈耦合混乱,不敢动,牵一发何止动全身重构不彻底,重构-烂尾,换个姿势重构-又烂尾……而要对这些代码进行彻底重构的话,最大的问题是很难有充裕的资源去大刀阔斧地一步到位,在逐步重构的同时,既要确保中间版本能够平滑过渡,同时还要持续交付新特性。所以,为了实施渐进式重构,我们需要一种增量升级的能力,先让新旧代码和谐共存,再逐步转化旧代码,直到整个重构完成这种增量升级的能力意味着我们能够对产品功能进行低风险的局部替换,包括升级依赖项、更替架构、UI 改版等。另一方面,也带来了技术选型上的灵活性,有助于新技术、新交互模式的实验性试错独立部署独立部署的能力在微前端体系中至关重要,能够缩小变更范围,进而降低相关风险因此,每个微前端都应具备有自己的持续交付流水线(包括构建、测试并部署到生产环境),并且要能独立部署,不必过多考虑其它代码库和交付流水线的当前状态:
就算旧的系统是按固定周期季度发布或手动发布的,甚至隔壁团队误发布了一个半成品或有问题的特性也无关紧要。也就是说,如果一个微前端已经准备好发布了,它就应该随时可发布,并且只由开发维护它的团队来定。
P.S.甚至还可以结合BFF模式实现更进一步的独立:
团队自治
除代码库及发布周期上的解耦之外,微前端还有助于形成完全独立的团队,由不同团队各自负责一块产品功能从构思到发布的整个过程,团队能够完全拥有为客户提供价值所需的一切,从而快速高效地运转为此,应该围绕业务功能纵向组建团队,而不是基于技术职能划分。最简单的,可以根据最终用户所能看到的内容来划分,比如将应用中的每个页面作为一个微前端,并交给一个团队全权负责。与基于技术职能或横向关注点(如样式、表单、校验等)组织的团队相比,这种方式能够提升团队工作的凝聚力:
二.实现方案
实现上,关键问题在于:
多个 Bundle 如何集成?
子应用之间怎样隔离影响?
公共资源如何复用?
子应用间怎样通信?
如何测试?
多 Bundle 集成
微前端架构中一般会有个容器应用(container application)将各子应用集成起来,职责如下:
- 渲染公共的页面元素,比如 header、footer
- 解决横切关注点(cross-cutting concerns),如身份验证和导航
- 将各个微前端整合到一个页面上,并控制微前端的渲染区域和时机
集成方式分为 3 类: - 服务端集成:如 SSR 拼装模板
- 构建时集成:如 Code Splitting
- 运行时集成:如通过 iframe、JS、Web Components 等方式
服务端集成
服务端集成的关键在于如何保证各部分模板(各个微前端)能够独立发布,必要的话,甚至可以在服务端也建立一套与前端相对应的结构:
每个子服务负责渲染并服务于对应的微前端,主服务向各个子服务发起请求
构建时集成
常见的构建时集成方式是将子应用发布成独立的 npm 包,共同作为主应用的依赖项,构建生成一个供部署的 JS Bundle然而,构建时集成最大的问题是会在发布阶段造成耦合,任何一个子应用有变更,都要整个重新编译,意味着对于产品局部的小改动也要发布一个新版本,因此,不推荐这种方式。
运行时集成
将集成时机从构建时推迟到运行时,就能避免发布阶段的耦合。
常见的运行时集成方式有:
- iframe
- JS:比如前端路由
- Web Components
虽然直觉上用 iframe 好像不太好(性能、通信成本等),但在这里确实是个合理选项,因为 iframe 无疑是最简单的方式,还天然支持样式隔离以及全局变量隔离。
但这种原生的隔离性,意味着很难把应用的各个部分联系到一起,路由控制、历史栈管理、深度链接(deep-linking)、响应式布局等都变得异常复杂,因而限制了 iframe 方案的灵活性。
另一种最常见的方式是前端路由,每个子应用暴露出渲染函数,主应用在启动时加载各个子应用的独立 Bundle,之后根据路由规则渲染相应的子应用。目前看来,是最灵活的方式。
还有一种类似的方式是Web Components,将每个子应用封装成自定义 HTML 元素(而不是前端路由方案中的渲染函数),以获得Shadow DOM带来的样式隔离等好处。
影响隔离
子应用之间,以及子应用与主应用间的样式、作用域隔离是必须要考虑的问题,常见解决方案如下: - 样式隔离:开发规范(如BEM)、CSS 预处理(如SASS)、模块定义(如CSS Module)、用 JS 来写(CSS-in-JS)、以及shadow DOM特性
- 作用域隔离:各种模块定义(如ES Module、AMD、Common Module、UMD)
资源复用
资源复用对于 UI 一致性和代码复用有重要意义,但并非所有的可复用资源(如组件)都必须在一开始就提出来复用,建议的做法是前期允许一定程度的冗余,各个 Bundle 在各自的代码库中创建组件,直到形成相对明确的组件 API 时再建立可供复用的公共组件
另一方面,资源分为以下 3 类:
- 基础资源:完全不含逻辑功能的图标、标签、按钮等
- UI 组件:含有一定 UI 逻辑的搜索框(如自动完成)、表格(如排序、筛选、分页)等
- 业务组件:含有业务逻辑
其中,不建议跨子应用复用业务组件,因为会造成高度耦合,增加变更成本
对于公共资源的归属和管理,一般有两种模式:
- 公共资源归属于所有人,即没有明确归属
- 公共资源归集中管理,由专人负责
从实践经验来看,前者很容易衍变成没有明确规范,且背离技术愿景的大杂烩,而后者会造成资源创建和使用的脱节,比较推荐的模式是开源软件的管理模式:
所有人都能补充公共资源,但要有人(或一个团队)负责监管,以保证质量、一致性以及正确性
应用间通信
通过自定义事件间接通信是一种避免直接耦合的常用方式,此外,React 的单向数据流模型也能让依赖关系更加明确,对应到微前端中,从容器应用向子应用传递数据与回调函数
另外,路由参数除了能用于分享、书签等场景外,也可以作为一种通信手段,并且具有诸多优势:
- 其结构遵从定义明确的开放标准
- 页面级共享,能够全局访问
- 长度限制促使只传递必要的少量数据
- 面向用户的,有助于依照领域建模
- 声明式的,语义上更通用(“this is where we are”, rather than “please do this thing”)迫使子应用之间间接通信,而不直接依赖对方
但原则上,无论采用哪种方式,都应该尽可能减少子应用间的通信,以避免大量弱依赖造成的强耦合
测试每个子应用都应该有自己的全套测试方案,特殊之处在于,除单元测试、功能测试外,还要有集成测试: - 集成测试:保证子应用间集成的正确性,比如跨子应用的交互操作
- 功能测试:保证页面组装的正确性
- 单元测试:保证底层业务逻辑和渲染逻辑的正确性
自下而上形成一个金字塔结构,每一层只需验证在其下层覆盖不到的部分即可
三、缺点
当然,这种架构模式并非百益而无一害,一些问题也随之而来:
- 导致依赖项冗余,增加用户的流量负担
- 团队自治程度的增加,可能会破坏协作
没有非常理想的解决办法,一种简单的方案是将公共依赖从(子应用的)构建产物中剔除,但又会引入构建时耦合。
操作/管理上的复杂性
在采用微前端之前,先要考虑几个问题:
- 现有的前端开发、测试、发布流程如何扩展支持很多个应用?
- 分散的,控制弱化的工具体系及开发实践是否可靠?
- 针对各式各样的前端代码库,如何建立质量标准?
总之,与之前不同的是,微前端将产生一堆小的东西,因此需要考虑是否具备采用这种方法所需的技术和组织成熟度
四、总结
类似于微服务之于后端,前端业务在发展到一定规模之后,也需要一种用来分解复杂度的架构模式,于是出现了微服务思想在前端领域的应用,即微前端。
主要目的在于:
- 技术架构上进一步的扩展性(模块边界清晰、依赖明确)
- 团队组织上的自治权
- 开发流程上能独立支付、独立交付
最大的意义上在于解锁了多技术栈并存的能力,尤其适用于渐进式重构中架构升级过渡期。
八、大前端
1.概念
大前端就是所有前端的统称,比如Android、iOS、web、Watch等,最接近用户的那一层也就是UI层,然后将其统一起来,就是大前端。大前端最大的特点在于一次开发,同时适用于所有平台,开发者不用为一个APP需要做Android和iOS两种模式而担心。大前端是web统一的时代,利用web不仅能开发出网站,更可以开发手机端web应用和移动端应用程序。
2.出现原因
前后端分离,当开发一个新产品的时候服务只需要写一次,但是面向用户的产品可能有很多,例如网站、安卓、IOS客户端、微信小程序等。由于各个平台使用的技术栈都不一样,代码无法复用,非常浪费人力、物力。而大前端的主要核心就是跨平台技术,有了跨平台技术,各个平台的差异性就磨平了,开发者只需要一套技术栈就可以开发出来适用于多个平台的客户端。
3.跨平台方案简介
Cordova/phoneGap、React Native、Weex、微信小程序、PWA和Flutter等,根据其原理性,可以分为四大类。
- H5+原生(Cordova、Ionic、微信小程序)
- JavaScript开发+原生渲染 (React Native、Weex、快应用)
- 自绘UI+原生(Flutter)
- 增强版Web App(PWA)
3.1 H5+原生混合开发
又叫Hybrid开发,利用这种模式开发的app有:微信、淘宝、美团、爱奇艺等。
这类框架主要原理就是将APP的一部分需要动态变动的内容通过H5来实现,通过原生的网页加载控件WebView (Android)或WKWebView(ios)来加载,H5部分是可以随时改变而不用发版,这样就解决了动态化的需求,同时,由于h5代码只需要一次开发,就能同时在Android和iOS两个平台运行,这也可以减小开发成本,我们称这种h5+原生的开发模式为混合开发。采用混合模式开发的APP我们称之为混合应用或Hybrid APP。
由于原生开发可以访问平台所有功能,而混合开发中,h5代码是运行在WebView中,而WebView实质上就是一个浏览器内核,其JavaScript依然运行在一个权限受限的沙箱中,所以对于大多数系统能力都没有访问权限,如无法访问文件系统、不能使用蓝牙等。所以,对于H5不能实现的功能,都需要原生去做。而混合框架一般都会在原生代码中预先实现一些访问系统能力的API, 然后暴露给WebView以供JavaScript调用,这样一来,WebView就成为了JavaScript与原生API之间通信的桥梁,主要负责JavaScript与原生之间传递调用消息,而消息的传递必须遵守一个标准的协议,它规定了消息的格式与含义,我们把依赖于WebView的用于在JavaScript与原生之间通信并实现了某种消息传输协议的工具称之为WebView JavaScript Bridge, 简称 JsBridge,它也是混合开发框架的核心。
混合应用的优点是动态内容是H5,使用web技术栈就可以开发,社区及资源丰富,缺点是性能不好,对于复杂用户界面或动画,webview不堪重任。
3.2 js开发+原生渲染
这类开源框架的代表主要是Facebook的React Native、阿里的Weex,当然也有未开源的美团的Picasso,以及快应用。
其主要优势为:
- 采用Web开发技术栈,社区庞大、上手快、开发成本相对较低
- 原生渲染,性能相比H5提高很多
- 动态化较好,支持热更新
缺点也很明显:
- 渲染时需要JavaScript和原生之间通信,在有些场景如拖动可能会因为通信频繁导致卡顿。
- js为脚本语言,执行时需要JIT,执行效率和AOT仍有差距
- 渲染依赖原生控件,不同平台的控件需要单独维护,并且当系统更新时,社区控件可能会滞后。(控件系统会受到原生UI系统限制。e.g.在Android中,手势冲突消歧规则是固定的,这在使用不同人写的控件嵌套时,手势冲突问题就很棘手了。)
3.3 React Native
React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,目前支持iOS和Android两个平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。
React Native的原理和React设计一致,React中虚拟DOM最终会映射为浏览器DOM树,而RN中虚拟DOM会通过 JavaScriptCore 映射为原生控件树。
JavaScriptCore 是一个JavaScript解释器,它在React Native中主要有两个作用:
- 为JavaScript提供运行环境。
- 是JavaScript与原生应用之间通信的桥梁,作用和JsBridge一样,事实上,在iOS中,很多JsBridge的实现都是基于 JavaScriptCore 。
而RN中将虚拟DOM映射为原生控件的过程中分两步:
- 布局消息传递; 将虚拟DOM布局信息传递给原生
- 原生根据布局信息通过对应的原生控件渲染控件树
由于React Native是原生控件渲染,所以性能会比混合应用中H5好很多,同时React Native是Web开发技术栈,只需维护一份代码,即可在多个平台上使用。
3.4 Weex
阿里2016年发布的跨平台移动端框架,思想及原理和React Native类似。最大的不同是语法层面,React Native使用React.js作为开发框架,而Weex则使用Vue.js作为开发框架。Vue和React堪称前端领域最火的JavaScript框架,它们的易用性和功能性都非常强大,Weex在淘宝上也有广泛的应用。
3.5 快应用
快应用是华为、小米、OPPO、魅族等国内9大主流手机厂商共同制定的轻量级应用标准,目标直指微信小程序。它也是采用JavaScript语言开发,原生控件渲染,与React Native和Weex相比主要有两点不同:
- 快应用自身不支持Vue或React语法,其采用原生JavaScript开发,其开发框架和微信小程序很像,值得一提的是小程序目前已经可以使用Vue语法开发(mpvue),从原理上来讲,Vue的语法也可以移植到快应用上。
- React Native和Weex的渲染/排版引擎是集成到框架中的,每一个APP都需要打包一份,安装包体积较大;而快应用渲染/排版引擎是集成到ROM中的,应用中无需打包,安装包体积小,正因如此,快应用才能在保证性能的同时做到快速分发。
自绘UI+原生
通过在不同平台实现一个统一接口的渲染引擎来绘制UI,而不依赖系统原生控件,所以可以做到不同平台UI的一致性。注意,自绘引擎解决的是UI的跨平台问题,如果涉及其它系统能力调用,依然要涉及原生开发。这种平台技术的优点如下:
- 性能高;由于自绘引擎是直接调用系统API来绘制UI,所以性能和原生控件接近。
- 灵活、组件库易维护、UI外观保真度和一致性高;由于UI渲染不依赖原生控件,也就不需要根据不同平台的控件单独维护一套组件库,所以代码容易维护。由于组件库是同一套代码、同一个渲染引擎,所以在不同平台,组件显示外观可以做到高保真和高一致性;另外,由于不依赖原生控件,也就不会受原生布局系统的限制,这样布局系统会非常灵活。
不足之处:
- 动态性不足;为了保证UI绘制性能,自绘UI系统一般都会采用AOT模式编译其发布包,所以应用发布后,不能像Hybrid和RN那些使用JavaScript(JIT)作为开发语言的框架那样动态下发代码。
Flutter
Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。 Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加原生扩展。
Flutter既不使用WebView,也不使用操作系统的原生控件。 相反,Flutter使用自己的高性能渲染引擎来绘制widget。这样不仅可以保证在Android和iOS上UI的一致性,而且也可以避免对原生控件依赖而带来的限制及高昂的维护成本。
Flutter使用Skia作为其2D渲染引擎,Skia是Google的一个2D图形处理函数库,包含字型、坐标转换,以及点阵图都有高效能且简洁的表现,Skia是跨平台的,并提供了非常友好的API,目前Google Chrome浏览器和Android均采用Skia作为其绘图引擎,值得一提的是,由于Android系统已经内置了Skia,所以Flutter在打包APK(Android应用安装包)时,不需要再将Skia打入APK中,但iOS系统并未内置Skia,所以构建iPA时,也必须将Skia一起打包,这也是为什么Flutter APP的Android安装包比iOS安装包小的主要原因。
但是Flutter也有不足之处,不支持动态下发代码和热更新。
4.大前端的趋势
大前端不仅会成为移动开发与Web前端的发展趋势,也将会是未来的显示设备终端的开发技术趋势。大前端将做更多的终端开发、工程化等工作,而不仅仅只是开发Web页面。大前端工程师将能搞定所有端上的开发。与充满争议的全栈工程师相比,它更具可操作性。但同时对开发者而言,要会更多的技术栈,比如原生开发者要学习html、css、js等前端知识,前端开发人员也要学习Android或iOS的原生开发技术,然后了解一下常见的跨平台技术,只有这样才能更好的融入到大前端的这个大家庭中。
九、云端一体化
概念
云端一体化,主要是打通客户端与云端资源(云函数、对象存储、文档型数据库等)的链路,让开发者可以在客户端上直接调用云资源,而无需构建应用后端服务,让应用开发变得更简单。
十、直出
1.概念
直出就是直接输出的意思。就是浏览器打开某个网页的时候,拿到的数据是服务器直接输出的,显示速度特别快。例如很多网页的秒开。
2. 过程
数据请求能放到 server 上,对于数据与HTML结合处理也可以在server上做,从而减少等待 JS 文件的加载时间。
主要处理如下:
- server上获取数据并将数据与页面模版结合,在服务端渲染成最终的HTML
- 返回最终的HTML展示
可以从下图看出,页面的首屏展示不再需要等待 JS 文件回来,优化减少了这块时间:
可以继续优化吗?
在页面文档不大情况下,可将CSS内联到HTML中,这是优化请求量的做法。直出稍微不同的是需要考虑的是服务端最终渲染出来的文档的大小,在范围内也可将 CSS 文件内联到 HTML 中。这样的话,便优化了 CSS 的获取时间,如下图:
3. 优势
直出能够将常用模式优化到剩下了一次 HTML 请求,加快首屏渲染时间,使用服务端渲染,还能够优化前端渲染难以克服的 SEO 问题。
十一、运行时,编译时
1.运行时
任何语言要运行都需要自己的运行时,Java 程序的运行时叫 Java Runtime,Android 程序的运行时叫 Android Runtime,而具体 Runtime 是个什么东西呢,就是说一个程序要在一个硬件或者平台上跑,就必须要有一个中间层用来把程序语言转换为机器能听懂的机器语言。
运行时就是代码跑起来了.被装载到内存中去了.
大概是这样:
2.编译时
编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字节码,C#中只有CLR能识别的MSIL.另外还有啥链接器.汇编器.为了了便于理解我们可以统称为编译器)