update: 目录调整
This commit is contained in:
314
13-前端性能优化/00-前言.md
Normal file
314
13-前端性能优化/00-前言.md
Normal file
@@ -0,0 +1,314 @@
|
||||
## 前言
|
||||
|
||||
### 前端实战开发的各个方面
|
||||
|
||||
前端实战开发包括很多方面,比如:
|
||||
|
||||
- 跨终端技术体系
|
||||
|
||||
- 前端监控体系
|
||||
|
||||
- 多终端可视化页面搭建体系
|
||||
|
||||
- 前端性能优化体系
|
||||
|
||||
- 具体业务的架构设计
|
||||
|
||||
- 前端通道建设
|
||||
|
||||
- 搭建前端工程化技术体系
|
||||
|
||||
- 网站前端基础架构升级
|
||||
|
||||
- 研发日PV达千万的超大流量前端项目
|
||||
|
||||
- 在 W3ctech、D2、FEDAY等技术大会中发表主题演讲
|
||||
|
||||
- 分享前端性能优化方面的经验和见解
|
||||
### 什么是前端性能优化
|
||||
|
||||
通常来讲,前端性能优化是指:从用户开始访问网站到整个页面完整地展现出来的过程中,通过各种优化策略和优化方法,让页面加载得更快,让用户的操作相应更及时,给用户更好的使用体验。
|
||||
|
||||
### 学习前端性能优化的难点
|
||||
|
||||
我们在网上找到的博客,有很多都只是对CSS、JS技术本身的优化,一旦涉及到App、后端、网络等不是很熟悉的领域,学习起来就比较困难了。结合具体业务开发的应用场景时,却不知从何下手。因此,我们需要要由点及面,学习全链路前端性能优化的知识体系和解决方案。
|
||||
|
||||
### 性能优化的重要性(程序员角度)
|
||||
|
||||
**大家都知道性能优化很重要,但是落实到具体,怎么去优化**?这就需要我们深入去了解前端技术背后的原理,才能总结出相应的优化方案,而且需要多年的经验积累。
|
||||
|
||||
当领导问:“为什么网页访问这么慢?”我们不能只是回答“网络不好”这么简单,每个程序员如果想要成长,就不能回避“性能优化”这个话题。很多人写了多年的代码,一直在构建样式、写业务逻辑。但是平凡的程序员之路,何时才是尽头呢?怎么才能从团队中脱颖而出呢?如何区分出平凡程序员/大牛程序员/架构师的分水岭呢?
|
||||
|
||||
公司评价一个程序员的价值,不是加班越多越好,也不是代码写得越多越好,而是看他是否能解决其他人解决不了的一些技术难题或者瓶颈。
|
||||
|
||||
掌握正确和主流的优化方案,是非常重要的。我们需要学习一些主流的前端性能优化技术方案,掌握性能优化技术,提升Web性能;进而到达前端技术圈的上游,提高自己的核心竞争力。
|
||||
|
||||
职场晋升时,我们也要想一想:大部分人都在写业务代码,和别人相比,我的核心竞争力在哪里?除了技术深度、综合素质之外,还有其他的吗?性能优化,绝对是不能忽视的一方面。而且它是贯穿于开发和维护的的全过程。
|
||||
### 性能优化的意义
|
||||
|
||||
|
||||
1、随着互联网的发展,**网页的内容越来越丰富,功能越来越强大,页面也越做越漂亮**;带来的问题是,访问速度和体验会收到影响。只有对网站进行持续不断的优化,才能保证网页的访问速度可以跟得上用户体验的需求。
|
||||
|
||||
2、**高性能**可以带来更高的**用户参与度**、**用户留存**,进而带来更高的**转化率**和**SEO排名**,更好的**用户体验**,最终带来更高的**业务收益**。
|
||||
|
||||
随着时间的推移,如果一个网站由于各种原因导致心梗越来越差,以至于用户每打开一个页面都要等待很长时间,甚至出现加载失败的情况,那么,不仅新用户不会沉淀下来,老用户也会纷纷离去,最终导致产品的加速衰败。
|
||||
|
||||
而且网站的加载快慢,最产品收入有着直接的影响。**有数据表明:网页加载时间在5秒内的网站比加载时间为19秒的网站,广告收入会增加近一倍**。也就是说,网站或者App的性能直接关系到产品的用户增长和收入增长。
|
||||
|
||||
正因为如此,我们才需要通过性能优化的技巧,并结合其他的技术手段来不断提高网站和App的用户体验,从而助力公司的业务增长;同时,我们也可以借此提升自己的技术实力,这对个人的职业成长也会以后很大的帮助。
|
||||
|
||||
3、只要产品上线了,随着**业务规模量和用户访问量的扩大**,性能优化就是不可回避的话题。在遇到性能问题时,有些人的解决办法是:用一些粗糙的手段把问题绕过去,但却给后面的人埋下了坑。有些人说出一句万能的话:
|
||||
|
||||
|
||||

|
||||
|
||||
### 相关案例
|
||||
|
||||
- [Amazon发现每100ms延迟导致1%的销量损失](https://www.gigaspaces.com/blog/amazon-found-every-100ms-of-latency-cost-them-1-in-sales/)。
|
||||
|
||||
- 歌地图首页文件从100KB减少到70KB,流量在第一周涨了10%,在接下来的三周涨了25%。
|
||||
|
||||
- 腾讯根据长期数据监控发现,页面一秒钟延迟会造成页面访问量下降9.4%,跳出率增加8.3%,转化率下降3.5%。
|
||||
|
||||
|
||||
|
||||
|
||||
### 优化是在做什么
|
||||
|
||||

|
||||
|
||||
优化的工作是围绕前端的基本工作原理展开的,包括:客户端和服务器端建立连接、加载资源、解析资源并渲染。
|
||||
|
||||
上方图片的来源:
|
||||
|
||||
- [The Cost Of JavaScript](https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e)
|
||||
|
||||
- [[译]JavaScript 的时间消耗](https://github.com/dwqs/blog/issues/59)
|
||||
|
||||
|
||||
### 优化标准
|
||||
|
||||
我们在做优化时,需要有一个量化标准,比如:
|
||||
|
||||
- loading 要做到什么效果、动画要达到什么效果才是好的?
|
||||
|
||||
- 所有的事件处理,要在什么时间内完成,才能给用户良好的体验?
|
||||
|
||||
### 收获
|
||||
|
||||
- 由浅入深:解读优化技术内幕。
|
||||
|
||||
- 流行+经典:了解技术背后的设计思想。
|
||||
|
||||
- 了解性能优化的关键环节,升级知识储备。
|
||||
|
||||
|
||||
- 理论+实践:掌握前端业界的流行且成熟的多种性能优化技术,脱颖而出。
|
||||
|
||||
- 了解大厂正在用的生产环境级别的高性能解决方案。
|
||||
|
||||
### 技术储备前提
|
||||
|
||||
- 掌握前端基础知识。
|
||||
|
||||
- 具备Web开发实战经验。
|
||||
|
||||
### 寻找性能瓶颈
|
||||
|
||||
- 了解性能指标,多快才算快。
|
||||
|
||||
- 利用测量工具和API
|
||||
|
||||
- 优化问题,重新测量。持续迭代。
|
||||
|
||||
### 移动端挑战多
|
||||
|
||||
- 移动端的硬件不如PC端,且网络不稳定。
|
||||
|
||||
- 屏幕尺寸和交互方式都是挑战。
|
||||
|
||||
- 移动端用户更佳缺乏耐心。而且,很多用户是利用碎片化时间访问网页。数据参考: **>3秒**的加载时间,导致 53%的跳出率(bounce rate)。
|
||||
|
||||
- 持续增长的移动端用户和电商业务。现在很多事情都是在移动端做的。
|
||||
|
||||
|
||||
|
||||
|
||||
## 前端性能优化全过程
|
||||
### 1、静态资源优化
|
||||
|
||||
静态资源优化包括html、css、js、图片等资源的性能优化。包括:
|
||||
|
||||
- 图片的应用场景和使用
|
||||
|
||||
- html、css、js的具体优化策略
|
||||
|
||||
|
||||
- 资源文件的优化:比如文件压缩合并策略、打包方案、版本号更新方案
|
||||
|
||||
- 前端工程化工具等。
|
||||
|
||||
### 2、页面渲染架构设计及相关的技术方案选型
|
||||
|
||||
按照技术方案的分类,包括:
|
||||
|
||||
- 前后端分离技术
|
||||
|
||||
- SPA单页应用
|
||||
|
||||
- BigPipe
|
||||
|
||||
- 同构直出
|
||||
|
||||
- PWA
|
||||
|
||||
- 页面加载策略
|
||||
|
||||
- 接口服务调优、接口缓存策略
|
||||
|
||||
- 大型网站背后的实际性能优化案例
|
||||
|
||||
- 前端组件化、模块化,加速业务开发
|
||||
|
||||
### 3、原生App优化、混合开发优化
|
||||
|
||||
- 浏览器的整体优化方案。比如导航条、登录态、滚动条优化等。
|
||||
|
||||
- 前端缓存策略和优化
|
||||
|
||||
- H5静态资源请求代理的技术原理
|
||||
|
||||
- H5离线技术,达到页面秒开的目标
|
||||
|
||||
- 混合式开发解决方案
|
||||
|
||||
- RN、小程序、flutter等
|
||||
|
||||
### 4、服务端与网络优化
|
||||
|
||||
- CDN 和 DNS 优化
|
||||
|
||||
- 如何减少 http 请求数、减少cookie大小
|
||||
|
||||
- nginx缓存配置和优化
|
||||
|
||||
- 开启和配置 gzip 压缩
|
||||
|
||||
- 如何开启全站 https
|
||||
|
||||
- 升级 Http2.0 的好处和方法
|
||||
|
||||
|
||||
### 5、研发流程优化
|
||||
|
||||
- 技术调用的方法
|
||||
|
||||
- 前后端接口约定、加快前后端接口联调
|
||||
|
||||
- 前端自动化测试
|
||||
|
||||
- 自动化部署和上线
|
||||
|
||||
- 从研发的整体流程层面梳理出提升研发效率的方式和方法。
|
||||
|
||||
|
||||
### 6、全链路质量监控体系建设
|
||||
|
||||
主要是对性能优化的结果进行衡量、打分、考核:
|
||||
|
||||
- 上线前,页面质量及时检测
|
||||
|
||||
- 上线后,页面性能和错误监控
|
||||
|
||||
- 线上运行时,页面的可用性监控
|
||||
|
||||
- 愿生App的性能和错误监控
|
||||
|
||||
## 前端性能优化包括哪些方面
|
||||
|
||||
### 1、性能优化指标与测量工具
|
||||
|
||||
- 行业标准
|
||||
|
||||
- 优化模型
|
||||
|
||||
- 性能测量工具:了解性能情况,并对比
|
||||
|
||||
- 性能相关APIs
|
||||
|
||||
### 2、渲染优化
|
||||
|
||||
- 现代浏览器的渲染原理
|
||||
|
||||
- 可优化的渲染环节和方法
|
||||
|
||||
|
||||
### 3、代码优化
|
||||
|
||||
|
||||
- JS优化:了解JS的开销、解析、优化方案,以及如何配合V8引擎做更有效的优化。
|
||||
|
||||
- html优化
|
||||
|
||||
- css优化
|
||||
### 4、资源优化
|
||||
|
||||
- 压缩合并
|
||||
|
||||
- 图片格式
|
||||
|
||||
- 图片加载
|
||||
|
||||
- 字体优化
|
||||
|
||||
|
||||
|
||||
### 5、构建优化
|
||||
|
||||
- webpack 优化配置
|
||||
|
||||
- 代码拆分
|
||||
|
||||
- 代码压缩
|
||||
|
||||
- 持久化缓存
|
||||
|
||||
- 监测与分析
|
||||
|
||||
- 按需加载
|
||||
|
||||
### 6、传输和加载优化
|
||||
|
||||
- gZip
|
||||
|
||||
- KeepAlive
|
||||
|
||||
- HTTP缓存
|
||||
|
||||
- Service Worker
|
||||
|
||||
- HTTP/2
|
||||
|
||||
- SSR 服务端渲染
|
||||
|
||||
- Nginx
|
||||
### 7、更多主流优化方案
|
||||
|
||||
|
||||
- SVG 优化图标
|
||||
|
||||
- FlexBox 布局
|
||||
|
||||
- 预加载
|
||||
|
||||
- 预渲染
|
||||
|
||||
- 窗口化提高列表性能
|
||||
|
||||
- 骨架屏
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
659
13-前端性能优化/01-性能优化的指标和工具.md
Normal file
659
13-前端性能优化/01-性能优化的指标和工具.md
Normal file
@@ -0,0 +1,659 @@
|
||||
|
||||
|
||||
## 性能指标和优化目标之:加载
|
||||
|
||||
性能指标:我们在性能优化过程中可以参考的标准。这些标准都是业界或者前人总结出来的指导性经验。我们可以参考这些指标,去指导我们自己的优化。
|
||||
|
||||
### 打开网站的初体验
|
||||
|
||||
我们以淘宝网站为例。
|
||||
|
||||

|
||||
|
||||
上图中,鼠标长按刷新图标,松开鼠标后,会弹出三个选项,我们选择最后一个选项“清空缓存并硬性重新加载”。PS:只有淘宝等少数网站有这个选项,其他很多网站都没有。
|
||||
|
||||

|
||||
|
||||
上图中,打开 chrome 调试工具,点开「设置」icon,下面的四个选项中,除了“Group by frame”之外,其他的三个选项都可以勾选上。
|
||||
|
||||
我们可以看到淘宝网站的一些指标:
|
||||
|
||||
- 资源量是 1.3M。
|
||||
- DOM加载完成时间(DOMContentLoaded):511ms。这是一个很关键的指标。
|
||||
- 其他资源的总加载时间是 1.05秒。
|
||||
|
||||
我们再来对比一下京东的:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 保存快照
|
||||
|
||||
network里的信息挺多,我们可以将其保存下来,留着以后做分析、做对照。
|
||||
|
||||

|
||||
|
||||
如上图所示,我们可以在 network 的空白处右键,选择“Save all as HAR with content”,将 network 信息保存为 **HAR**文件格式。
|
||||
|
||||
**HAR是一种标准的Web格式,用户保存性能测试的结果。里面的数据是json格式。**
|
||||
|
||||
我们可以使用第三方的 HAR 分析软件来打开 HAR 文件,比如:
|
||||
|
||||
- [Google 提供的 HAR 分析器](https://toolbox.googleapps.com/apps/har_analyzer/?lang=zh-CN)
|
||||
|
||||
- Fiddler 抓包工具
|
||||
|
||||
注意,HAR 文件包含了一些敏感信息:
|
||||
|
||||

|
||||
|
||||
### 瀑布图 Waterfall
|
||||
|
||||

|
||||
|
||||
瀑布图可以非常直观地把网站的加载过程,用自上而下的方式表达出来,就像瀑布一样。
|
||||
|
||||
瀑布图有两中解读方式:一种是横向看,一种是纵向看。
|
||||
|
||||
**1、横向看**:
|
||||
|
||||
横向看的是具体的资源,每一行代表某个资源的加载信息。里面有一些色块来表达加载的过程,每个块的颜色不同。也就是说资源的下载不是单一的过程,而是经历了很多环节。
|
||||
|
||||
为了了解资源的具体加载过程,我们把鼠标悬浮在第一个资源的色块上,可以看见一个详情列表:
|
||||
|
||||

|
||||
|
||||
(1)等待:
|
||||
|
||||
- Queueing:排队。浏览器会对资源的请求做优先级排序。
|
||||
|
||||
(2)连接:
|
||||
|
||||
- DNS Lookup:DNS域名解析。每个资源都有域名,对域名做DNS解析,然后找到对应服务器的IP地址。
|
||||
|
||||
- initial connection:客户端和服务器之间建立TCP连接。
|
||||
|
||||
- SSL证书:该网站为了保证安全性,使用了 https 协议,启用了SSL证书。启用之后,需要做安全认证(SSL协商),这个过程也会耗时。到这里位置,我们可以看到,在请求资源之前,有很多的前置步骤。
|
||||
|
||||
(3)请求和响应:
|
||||
|
||||
- Request sent:到这一步,真正开始请求资源。
|
||||
|
||||
- Waiting(**TTFB**):资源从请求到响应,有一个等待的时间。
|
||||
|
||||
- Content Download:收到响应后,资源的下载时间。如果值越大,表明下载时间越长。有些同步加载的资源会造成阻塞,导致网页的整体加载时间过长,让用户等待太久。
|
||||
|
||||
**TTFB** 是一个很重要的指标,它表示的是:请求发出到响应,到底要经历多久。TTFB 可以给我们一个很直观的感受,我们网站的请求和响应到底是快还是慢,很大程度上是由 TTFB 决定。
|
||||
|
||||
影响 TTFB 的因素是什么呢?比如:
|
||||
|
||||
- 后台的处理能力的响应速度。
|
||||
|
||||
- 网络状况:是否有网络延迟。
|
||||
|
||||
**2、纵向看**:(主要看两点)
|
||||
|
||||
(1)看资源与资源之间的联系:如果发生阻塞,说明资源可能是串行地按顺序加载。可以**按需要适当调整为并行**。
|
||||
|
||||
(2)看关键的时间节点。Waterfall 中有**两根时间线**:蓝色的线是 DOM 加载完成的时间,红色的线是所有资源加载完成的时间。
|
||||
|
||||
|
||||
|
||||
## 性能指标和优化目标之:交互
|
||||
|
||||
上面的内容讲的是**加载**的性能,还有一个需要关注的性能指标是**交互**。也就是网站加载完成后,用户真正开始使用这个网站过程中的的交互体验。
|
||||
|
||||
关于交互体验的性能,我们需要关注的是:
|
||||
|
||||
- 交互动作的**响应时间**要短:比如点击按钮后的弹窗、在搜索框里输入关键字后的搜索结果。
|
||||
|
||||
- 页面滚动要流畅:可以查看 FPS 帧率。
|
||||
|
||||
- 异步请求接口的完成时间要短:比如关注/取关主播的响应、领取红包的操作。
|
||||
|
||||
### FPS帧率、FRS
|
||||
|
||||
这里首先科普两个概念:
|
||||
|
||||
- 刷新率:显示器每秒有多少帧画面。大多数显示器的刷新率是60帧/秒(即60hz)。
|
||||
- 帧率(FPS:frames per second):视频或者动画的内容本身,每秒有多少帧。由显卡输出帧率。
|
||||
|
||||
上面的两个参数中,不要把「刷新率」和「帧率」弄混了。「刷新率」是屏幕的参数,「帧率」是图像、视频等内容的参数。人眼最终看到的效果,是以最低的参数为准的。
|
||||
|
||||
目前,市场主流手机和电脑屏幕的刷新率基本都是60Hz,即每秒显示60帧画面。也就是说,当我们在使用手机的时候,本质上是手机在连续播放一张张静态图片,每秒播放60张,让肉眼误认为眼前的画面在动。
|
||||
|
||||

|
||||
|
||||
持续滑动的过程中,如果页面输出到显示器的帧率低于60帧/秒,则人眼会感觉卡顿。
|
||||
|
||||
那么,在浏览器中如何实时显示内容的 FPS 参数呢?打开浏览器的控制台后,按住快捷键「Cmd + Shift + P」,然后输入 `frame`,选择`Show frames per second(FPS) meter`。如下:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**温馨提示**:
|
||||
|
||||
从 2020年7月起,chrome 官方已经取消了 fps参数的显示,改为了 [FRS](https://twitter.com/addyosmani/status/1281483292026400768):
|
||||
|
||||

|
||||
|
||||
FRS参数观察的是丢帧率:
|
||||
|
||||

|
||||
|
||||
|
||||
Chrome官方给我们提供了下面这个网站,用于观察 FPS 效果:
|
||||
|
||||
- <http://googlesamples.github.io/web-fundamentals/tools/chrome-devtools/rendering-tools/forcedsync.html>
|
||||
|
||||
如果实在想要看fps,我们可以借助第三方的 [chrome 插件]()来查看 fps参数。
|
||||
|
||||
## 用 RAIL 模型测量性能
|
||||
|
||||
RAIL 模型是Google提出的可以量化性能的测量**标准**。我们做性能优化时,要尽可能到这个标准。
|
||||
|
||||
在做性能优化的时候,我们需要有人告诉我们:做到多好才算好?有没有一些通用的标准?而 RAIL 模型 可以给我们带来量化的指标。
|
||||
|
||||
**RAIL 模型包括四个方面**:
|
||||
|
||||

|
||||
|
||||
- Response:响应
|
||||
|
||||
- Animation:动画
|
||||
|
||||
- Idle:空闲时间
|
||||
|
||||
- load:加载
|
||||
|
||||
参考链接:
|
||||
|
||||
- [[Web翻译]用RAIL模型测量性能](https://juejin.cn/post/6872474167543857165)
|
||||
|
||||
- <https://web.dev/rail/>
|
||||
|
||||
**RAIL 的目标**:
|
||||
|
||||
- 让良好的用户体验成为性能优化的目标
|
||||
|
||||
接下来,我们再看看看 RAIL 的评估标准。
|
||||
|
||||
### 1、响应
|
||||
|
||||
**目标**:处理用户发起的响应,应该在 50ms 内完成。
|
||||
|
||||
**准则**:
|
||||
|
||||
- 在50毫秒内处理用户输入事件。这适用于大多数输入,如点击按钮、切换表单控件或启动动画。这不适用于触摸拖动或滚动。
|
||||
|
||||
- 对于需要超过50毫秒才能完成的操作,需要提供反馈。
|
||||
|
||||
|
||||

|
||||
|
||||
如上图所示,Google经过大量研究发现,用户能够接受的最高延时是100ms。所以,从用户发起交互请求(输入任务)后,前端最好能在100ms内给出反馈。
|
||||
|
||||
**但是我们的预算只有50毫秒**。因为应用程序在接收到输入任务的时候,不一定会马上着手处理,它可能还有其他工作正在进行,这意味着当前的输入任务可能需要排队50ms左右。所以我们真正能处理这个请求的时间,并没有100ms。
|
||||
|
||||
|
||||
### 2、动画
|
||||
|
||||
**目标**:在10毫秒或更短的时间内制作出动画中的每一帧。(即:100帧/秒。)
|
||||
|
||||
我们知道,当动画的帧率是 >= 60帧/秒 的时候,人眼才不会觉得卡顿。此时的理论值为 1000毫秒/60帧 = 16.6 毫秒/帧。
|
||||
|
||||
10毫秒和16毫秒之间,隔了6秒。这6秒是什么呢?因为浏览器需要大约6毫秒的时间来渲染每一帧,所以,每一帧的准则建议是10毫秒,而不是 16.6毫秒。
|
||||
|
||||
假设动画本身是60帧/秒,那么,最终渲染出来的效果可能只有 45帧/秒。
|
||||
|
||||
**广义的动画**:
|
||||
|
||||
动画不仅仅是花哨的UI效果。每一种交互都被认为是动画。比如:
|
||||
|
||||
- 视觉动画
|
||||
|
||||
- 滚动
|
||||
|
||||
- 拖动、平移元素、放大图片等。
|
||||
|
||||
### 3、空闲时间
|
||||
|
||||
**目标**:最大化闲置时间,增加页面在50毫秒内响应用户输入的几率。
|
||||
|
||||
这个空闲时间,是和上面的第一点“响应”是结合在一起的。只有空闲足够多,当用户的交互来的时候,我们才能有足够的时间进行处理。
|
||||
|
||||
**准则**:
|
||||
|
||||
- 利用空闲时间做延迟加载。例如,页面在初始化的时候,尽可能少的加载数据,然后利用空闲时间加载其余部分。
|
||||
|
||||
- 在空闲时间内处理任务,时间不能超过50毫秒。否则,就阻塞了用户做其他的输入请求,导致卡顿。
|
||||
|
||||
- 如果用户在闲置时间工作期间与页面进行交互,那么这个交互应始终处于最高优先级,并中断闲置时间工作。
|
||||
|
||||
### 4、加载
|
||||
|
||||
**目标**:在5秒或更短的时间内加载页面并可以交互。
|
||||
|
||||
**准则**:
|
||||
|
||||
- 这里的5秒包括:加载、解析、渲染,并确保用户可以交互。
|
||||
|
||||
- 加载的过程中,可以使用loading框、进度条、骨架屏等方式缓解用户焦虑。
|
||||
|
||||
## 使用Chrome DevTools 分析性能
|
||||
|
||||
现在主流的性能测量工具:
|
||||
|
||||
- Chrome DevTools:开发调试、分析性能。
|
||||
|
||||
- Lighthouse 网站整体质量评估。
|
||||
|
||||
- WebPageTest:给网站提供多个地点的测试,以及全面的性能报告。
|
||||
|
||||
这一段,我们先来讲一讲 Chrome DevTools 。
|
||||
|
||||
大家平时在用 Chrome DevTools 的时候,一般使用来开发调试、查看 DOM、css、接口请求等,但其实,这个工具非常强大。
|
||||
|
||||
### size:文件大小分析
|
||||
|
||||

|
||||
|
||||
可以把size从到小排序,看看哪个资源的文件较大。
|
||||
|
||||
另外,上图中的横线处说明:该文件在网络传输的时候会做压缩(125kb),拿到资源之后再解压还原(526kb)。
|
||||
|
||||
|
||||
|
||||
### performance:性能表现
|
||||
|
||||

|
||||
|
||||
preformance的两个作用:
|
||||
|
||||
- Record button:记录页面加载、用户交互等全过程,直到我们手动点击停止按钮。
|
||||
- Reload button:记录页面从刷新到资源加载完成的过程。会自动停止记录。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
参数解读:
|
||||
|
||||
- Timing:关键的时间节点。
|
||||
|
||||
- Main:主线程做了哪些任务,以及调用关系。
|
||||
|
||||
Timing参数中,尤其注意看`DCL`(DOMContentLoaded),即DOM加载完成的时间节点。我们可以通过`Main`参数看看DOM在加载完成之前,都做了些什么事情。很有可能就是这些事情导致 `DCL`的时间过晚。
|
||||
|
||||
我们可以翻到`Main`里的最后一行(即最终调用的位置),往往这个位置就是我们自己写的代码。
|
||||
|
||||
|
||||
|
||||
### Diable cache
|
||||
|
||||

|
||||
|
||||
上图中的`Diable cache`是一个很重要的设置选项。
|
||||
|
||||
勾选`Diable cache`:
|
||||
|
||||
- 不走缓存,相当于页面初次访问。
|
||||
- 如果你希望改的代码立即生效,就一定要勾选上。
|
||||
|
||||
不勾选`Diable cache`:
|
||||
|
||||
- 走缓存,相当于页面二次、三次访问。
|
||||
- 很多时候,我们需要关心用户在第二次、第三次访问时候,他的访问速度如何、性能如何、我们设置的缓存有没有生效。此时就不要勾选上。
|
||||
|
||||
### 模拟网络情况
|
||||
|
||||

|
||||
|
||||
模拟网络状况(自定义参数):
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### Performance monitor
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 快捷键ESC
|
||||
|
||||
按住快捷键ESC,会列出其他常用的功能菜单:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 使用 WebPageTest 评估网站性能
|
||||
|
||||
|
||||
|
||||
程序员经常说的有句话是:“我这儿能打开啊。我这儿不报错呀。”大家应该都懂这个梗,这就是为什么,我们要借助第三方的测试工具,而不仅仅只是自己电脑上访问正常就ok了。
|
||||
|
||||
我们需要借助 WebPageTest 这样的第三方测试工具,去模拟各种用户的真实场景。
|
||||
|
||||
|
||||
### WebPageTest 使用
|
||||
|
||||
网址:<https://www.webpagetest.org>
|
||||
|
||||

|
||||
|
||||
|
||||
WebPageTest 在世界各地提供了非常多的服务器,在每个服务器上部署了不同的浏览器,可以让我们有针对性的做测试。如果你做的是一款国际化网站,那更有必要使用一下了。
|
||||
|
||||
我们以JD网站举例:
|
||||
|
||||

|
||||
|
||||
按照上面的选项配置完成后,点击右侧的「Start Test」即可开始测试。然后等待:
|
||||
|
||||

|
||||
|
||||
### WebPageTest 报告分析
|
||||
|
||||
淘宝网站性能测试报告:
|
||||
|
||||
- 2020年6月:https://webpagetest.org/result/200616_JK_78eebda338285ffe0c2e154ca5032839/
|
||||
|
||||
- 2021年1月:https://www.webpagetest.org/result/210115_DiCB_f1344d732760365151755e89765b2d37/
|
||||
|
||||
JD网站性能测试报告:
|
||||
|
||||
- 2021年1月:https://www.webpagetest.org/result/210115_DiGT_8d7370e91230b7d077e40b7aafb485a5/
|
||||
|
||||
拿到 WebPageTest 报告之后,我们来看看报告里的几个重点指标。
|
||||
|
||||

|
||||
|
||||
1、摘要里的参数:(如上图)
|
||||
|
||||
- First Byte:第一个请求的响应时间。可以反映后台的处理能力,以及网络回路的情况。
|
||||
- Start Render:从白屏到首次渲染的时间。
|
||||
- Speed Index:速度指数。
|
||||
- **Total Blocking Time**:页面被阻塞,导致用户不能交互的累计时间。
|
||||
|
||||

|
||||
|
||||
2、详情里的参数:**First View**。
|
||||
|
||||
First View展示的是:首次访问时,总的加载时间。这里面提供的瀑布图,比 chrome DevTools里提供的更为详细。
|
||||
|
||||
点击进入 First View 的详情之后,可以看到:所有的资源请求,都会在这里列出来。如下:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
- page is Interactive:页面在加载的过程中,大部分时间段,用户都是可以交互的。这是非常有用的一个指标。
|
||||
- Brower Main thread:浏览器主线程的占用情况。可以看看空闲的时间多不多。
|
||||
- CPU Utilization:CPU的使用情况。
|
||||
- 多张图片的资源请求。
|
||||
|
||||

|
||||
|
||||
上图中,我们可以看到:多张图片的开始请求时间都是相同的。也就是说,如果让资源做**并行加载**,我们就可以加大地减少加载时间,**最终所消耗的时间就由最大的图片来决定**。这是一个很好的优化技巧,至于具体是怎么实现的,可以自行了解。
|
||||
|
||||
|
||||
另外,我们看到,有一部分的请求,被高亮出来了:
|
||||
|
||||

|
||||
|
||||
|
||||
上面这张图的意思是:302表示重定向,也就是说,这个资源已经不在原来请求的位置了,需要重定向才能找到真实的位置。这个地方其实可以做一个优化:
|
||||
|
||||
> 不需要去访问之前的无效的资源,可以直接去访问重定向后的那个资源。
|
||||
|
||||
### 局域网部署 WebPageTest 工具
|
||||
|
||||
如果我们开发的页面,还没有上线,公网则无法访问。这个时候我们也想通过WebPageTest看看网站的性能,那要怎么办呢?
|
||||
|
||||
我们可以在局域网部署 WebPageTest 工具,具体方法可自行研究。
|
||||
|
||||
## 使用LightHouse分析性能
|
||||
|
||||
我们之所以使用不同的性能测量工具,是因为他们都有不同的特点。WebPageTest 可以生成详细的性能测试报告;而 接下来要讲的 lighthouse 不仅可以帮我们生成测试报告,还可以给出一些针对性的优化建议。
|
||||
### Lighthouse 介绍
|
||||
|
||||

|
||||
|
||||
lighthouse 是 chrome 浏览器的一个性能测量工具。我们先来看看它的性能指标,至于它具体使用,后续的内容再详细介绍。
|
||||
|
||||
|
||||
淘宝跑分举例:
|
||||
|
||||
|
||||

|
||||
|
||||
京东跑分举例:
|
||||
|
||||

|
||||
|
||||
|
||||
Lighthouse 跑分里,最重要的两个指标如下:
|
||||
|
||||
- **First Contentful Paint**:**从白屏到第一次出现内容的时间。**我们可以看到,上面提供了一些加载过程的截图,10屏里如果只有1到2屏是白屏,说明体验还是可以的。
|
||||
|
||||
- **Speed Index**:速度指数。
|
||||
|
||||
我们不需要关心这个指数是怎么来的,因为背后涉及一套很复杂的公式,我们暂时只需关注这个数值。
|
||||
|
||||
Speed Index 标准为4秒(超过4秒算比较慢的),我们测的淘宝的 speed index 是0.5s,很快了。但我们要结合网站本身的性质来权衡。并不是分数越高性能越高,比如百度这样的网站,页面上的内容很少,测出来的分数肯定很完美。而淘宝需要展示很多内容给用户看。所以,这个指标只是一个指导作用,并不一定能够达到最优的数值。
|
||||
|
||||
另外,Lighthouse 还会给出一些优化建议:
|
||||
|
||||
- Opportunities:优化建议。
|
||||
|
||||
- Diagnostics:问题诊断。
|
||||
|
||||
- Passed audits:表示这部分没有问题。
|
||||
|
||||
### 举例:确认某个JS 是否必须在首屏加载
|
||||
|
||||
就拿B站来举例,来看看它的lighthouse报告:
|
||||
|
||||
|
||||

|
||||
|
||||
上图中给出了一个优化建议:有些JS文件不是首屏加载必须的。
|
||||
|
||||

|
||||
|
||||
我们随便拿一个JS文件来测试(比如上图中,Header标签里的JS文件)。做法如下:
|
||||
|
||||

|
||||
|
||||
如上图所示,在 chrome 控制台输入快捷键「Cmd + Shift + P」,然后输入文本`block`,选择`Show Network request blocking`:
|
||||
|
||||

|
||||
|
||||
按照上面的步骤添加规则,点击add后,效果如下:
|
||||
|
||||

|
||||
|
||||
|
||||
然后,我们切换到控制台的 network面板,并刷新页面:
|
||||
|
||||

|
||||
|
||||
然后观察这个js资源是不是首屏加载所必须的。但我们也不能就此定论说这个资源一定可以延迟加载,也许它就是想让页面在一开始loading的时候就捕获日志。
|
||||
|
||||
对于我们自己的网站,这个资源是首屏加载必须的吗?一定要在第一时间加载吗?需要根据特定的业务做衡量。
|
||||
|
||||
|
||||
### 通过npm运行 Lighthouse工具
|
||||
|
||||
```bash
|
||||
# 安装
|
||||
npm install -g lighthouse
|
||||
|
||||
# 执行
|
||||
lighthouse https://www.jd.com
|
||||
|
||||
# 输出性能检测报告
|
||||
Generating results...
|
||||
html output witten to /Users/smyh/Documents/wpt-mac-agent/www.jd.com._2021-01-16_09-00-00.html
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 实时动态测量性能的API
|
||||
|
||||
Chrome DevTools能够检测各种性能参数,其实也是调用了一些性能相关的标准API。我们自己也可以直接在代码里调用这些api。
|
||||
|
||||
通过 `performance`对象提供的API,我们可以实时的、精细化、自定义测量性能,获取相应的参数。也可以把这些性能参数,打印到控制台,或者实时上报给后台监控系统。
|
||||
|
||||
### performance:获取常见性能参数
|
||||
|
||||
常见性能参数,计算公式如下:
|
||||
|
||||
> 时间戳1减去时间戳2,得到的差值,就是我们想要看到的耗时。
|
||||
|
||||
- DNS 解析耗时: domainLookupEnd - domainLookupStart
|
||||
|
||||
- TCP 连接耗时: connectEnd - connectStart
|
||||
|
||||
- SSL 安全连接耗时: connectEnd - secureConnectionStart
|
||||
|
||||
- 网络请求耗时 (TTFB): responseStart - requestStart
|
||||
|
||||
- 数据传输耗时: responseEnd - responseStart
|
||||
|
||||
- DOM 解析耗时: domInteractive - responseEnd
|
||||
|
||||
- 资源加载耗时: loadEventStart - domContentLoadedEventEnd
|
||||
|
||||
- First Byte时间: responseStart - domainLookupStart
|
||||
|
||||
- 白屏时间: responseEnd - fetchStart
|
||||
|
||||
- 首次可交互时间(**TTI**): domInteractive - fetchStart
|
||||
|
||||
- DOM Ready 时间: domContentLoadEventEnd - fetchStart
|
||||
|
||||
- 页面完全加载时间: loadEventStart - fetchStart
|
||||
|
||||
- http 头部大小: transferSize - encodedBodySize
|
||||
|
||||
- 重定向次数:performance.navigation.redirectCount
|
||||
|
||||
- 重定向耗时: redirectEnd - redirectStart
|
||||
|
||||
比如说,如果我们想要获取 TTI参数,代码可以这样写:
|
||||
|
||||
```javascript
|
||||
// 计算一些关键的性能指标
|
||||
window.addEventListener('load', (event) => {
|
||||
// Time to Interactive
|
||||
let timing = performance.getEntriesByType('navigation')[0];
|
||||
console.log(timing.domInteractive);
|
||||
console.log(timing.fetchStart);
|
||||
|
||||
let diff = timing.domInteractive - timing.fetchStart;
|
||||
console.log("TTI: " + diff); // 打印 TTI 参数
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 观察长任务
|
||||
|
||||
```javascript
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
console.log(entry)
|
||||
}
|
||||
})
|
||||
|
||||
observer.observe({entryTypes: ['longtask']})
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 页面可见性的状态监听
|
||||
|
||||
使用场景举例:
|
||||
|
||||
- 比如说,我们正在做一个视频网站(或者游戏页面)。如果用户当前没有在看这个视频,而是切换别的页面了。此时,我们可以对视频做节流等处理,避免造成性能的浪费。等用户再回到当前页面之后,再恢复之前的状态。
|
||||
- 当设备进入待机模式时(用户按下电源键关闭屏幕),网站想要关闭设备声音。
|
||||
|
||||
针对这种场景,我们可以使用`visibilitychange`进行监听:
|
||||
|
||||
```javascript
|
||||
// 见面可见性的状态监听
|
||||
let vEvent = 'visibilitychange';
|
||||
if (document.webkitHidden != undefined) {
|
||||
// webkit prefix detected
|
||||
vEvent = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
function visibilityChanged() {
|
||||
if (document.hidden || document.webkitHidden) {
|
||||
console.log("Web page is hidden.")
|
||||
} else {
|
||||
console.log("Web page is visible.")
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener(vEvent, visibilityChanged, false);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 网络状况监听
|
||||
|
||||
使用场景举例:
|
||||
|
||||
- 高清图片按需加载:如果用户的网络条件较好,就加载高清图片资源;如果网络条件不好,就加载文件较小的图片资源。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
||||
|
||||
var type = connection.effectiveType;
|
||||
|
||||
function updateConnectionStatus() {
|
||||
// type是之前的网络状态,connection.effectiveType是当前最新的网络状态
|
||||
console.log("Connection type changed from " + type + " to " + connection.effectiveType);
|
||||
|
||||
type = connection.effectiveType;
|
||||
}
|
||||
|
||||
connection.addEventListener('change', updateConnectionStatus);
|
||||
```
|
||||
|
||||
打印结果举例:
|
||||
|
||||
```
|
||||
Connection type changed from 4g to 3g
|
||||
```
|
||||
|
||||
### 检测元素的可见状态,做曝光埋点
|
||||
|
||||
我们可以通过`IntersectionObserver:`这个API来检测元素的可见状态:
|
||||
|
||||

|
||||
|
||||
做曝光上报的埋点:判断某个DOM(或者某个楼层)是否出现在视窗中,出现了就收集数据上报给服务端。
|
||||
|
||||
本质就是要计算某一元素和另一元素(视窗)的相对位置/相对可视状态,然后进行一些操作(一般是上报给服务端)。
|
||||
|
||||
参考:
|
||||
|
||||
- [前端埋点之曝光实现](https://cnodejs.org/topic/5e0a0edb0696c446bf650dec)
|
||||
- [点击埋点和曝光卖点的封装](https://github.com/Hugohui/vueTrackSdk)
|
||||
|
||||
|
||||
209
13-前端性能优化/02-浏览器渲染机制.md
Normal file
209
13-前端性能优化/02-浏览器渲染机制.md
Normal file
@@ -0,0 +1,209 @@
|
||||
|
||||
|
||||
|
||||
## 前言
|
||||
|
||||
**渲染机制**包括的内容:
|
||||
|
||||
- 什么是DOCTYPE及作用
|
||||
|
||||
- 浏览器渲染过程。面试经常会问:在浏览器中输入url,发生了哪些事情。其中有一部就是浏览器的渲染过程。
|
||||
|
||||
- Reflow:重排。面试官问完了渲染机制,一般会紧接着问重排Reflow,你可千万别说你没听过。
|
||||
|
||||
- Repaint:重绘
|
||||
|
||||
- Layout:布局。这里的Layout指的是浏览器的Layout。
|
||||
|
||||
## 什么是DOCTYPE及作用
|
||||
|
||||
### 定义
|
||||
|
||||
**DTD**(Document Type Definition):文档类型定义。
|
||||
|
||||
是一系列的语法规则,用来定义XML或者(X)HTML文件类型。**浏览器会使用DTD来判断文本类型**,决定使用何种协议来解析,以及切换浏览器模式。(说白了就是:DTD就是告诉浏览器,我是什么文档类型,你要用什么协议来解析我)
|
||||
|
||||
**DOCTYPE**:用来声明DTD规范。
|
||||
|
||||
一个主要的用途便是文件的合法性验证。如果文件代码不合法,那么浏览器解析时便会出现一些差错。(说白了,DOCTYPE就是用来声明DTD的)
|
||||
|
||||
|
||||
### 常见的DOCTYPE声明有几种
|
||||
|
||||
> 面试官紧接着会问,常见的 DOCTYPE 有哪些,以及 HTML5 的 DOCTYPE 怎么写。
|
||||
|
||||
1、**HTML 4.01 Strict**:(严格的)
|
||||
|
||||
```html
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
```
|
||||
|
||||
PS:该DTD包含所有的HTML元素和属性,但不包括展示性的和弃用的元素(比如 font、u下划线等,这些是被废弃了的)。
|
||||
|
||||
2、**HTML 4.01 Transitional**:(传统的)
|
||||
|
||||
```html
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
```
|
||||
|
||||
PS:该DTD包含所有的HTML元素和属性,但包括展示性的和弃用的元素(比如 font、u下划线等)。
|
||||
|
||||
|
||||
3、HTML 5:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
```
|
||||
|
||||
|
||||
**总结:**
|
||||
|
||||
面试时,不会让你写出 HTML 4.01的写法,因为大家都记不住。但是要记住 HTML 5 的写法,别看它简单,知道的人还真不多。
|
||||
|
||||
面试时,可以这样回答: HTML 4.01 中有两种写法,一种是严格的,一种是传统的;并且答出二者的区别。 HTML 5的写法是`<!DOCTYPE html>`。
|
||||
|
||||
|
||||
|
||||
|
||||
## 浏览器的渲染过程
|
||||
|
||||
|
||||
|
||||
### 渲染树
|
||||
|
||||

|
||||
|
||||
> 上方图片的来源:[Google 官方 | 渲染树构建、布局及绘制](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction?hl=zh-cn)
|
||||
|
||||
**渲染树**包含了网页中有哪些节点、节点的从属关系、以及节点的CSS样式(大小、颜色等)。
|
||||
|
||||
浏览器下载完html文档之后,第一步是先将其解析成文本。而html标签是由一对一对的尖括号表述的,可以被浏览器解析为有含义的标记。这些标记被翻译成节点对象,存放到链型数据结构中。这些节点被称之为**DOM对象**,这个链型数据结构就是**渲染树**。
|
||||
|
||||
### 渲染过程(重要)
|
||||
|
||||
浏览器的渲染过程非常复杂,面试时找重点说就行,不然太耗时间。如何快速简洁地描述清楚,是关键。来看看下面这张图。
|
||||
|
||||

|
||||
|
||||
渲染过程中,涉及到以下几个概念:
|
||||
|
||||
- DOM树(DOM Tree):浏览器将HTML标签解析成树形的数据结构。DOM树包含了有哪些节点,以及节点之间的从属关系(嵌套关系)。
|
||||
|
||||
- CSSOM(CSS Rule Tree):浏览器将CSS解析成树形的数据结构。CSSOM包含了节点的CSS样式(大小、颜色等)。
|
||||
|
||||
- 渲染树(Render Tree): DOM 树与 CSSOM 树**合并**后形成渲染树。渲染树只包含渲染网页所需的节点(但并不知道位置)。
|
||||
|
||||
- 布局(Layout): 计算出每个节点在屏幕中的**位置和大小**。
|
||||
|
||||
- 绘制(Painting):按照算出来的规则,通过显卡,把内容画出来。
|
||||
|
||||
- composite:合成。浏览器在绘制的时候,一开始不会把所有的内容都画在同一层上。需要把这些内容画在不同的曾上,最终合并到一起,并显示在屏幕上。
|
||||
|
||||
参考链接:
|
||||
|
||||
- [浏览器渲染原理及流程](http://www.cnblogs.com/slly/p/6640761.html)
|
||||
|
||||
### 关键渲染路径
|
||||
|
||||
说到渲染,就不得不提到“关键渲染路径”,它描述的是渲染从触发到绘制的过程。浏览器渲染经历了五个阶段:
|
||||
|
||||
> JavaScript/CSS --> Style --> Layout --> Paint --> Composite
|
||||
|
||||

|
||||
|
||||
> 上方图片的来源:<https://developers.google.com/web/fundamentals/performance/rendering>
|
||||
|
||||
关键渲染路径描述的是渲染从触发到绘制的全过程,一共经历了五个阶段:
|
||||
|
||||
(1)**触发视觉的变化:**通过JS、CSS代码来**触发**页面上的视觉变化。比如通过 jQuery添加节点、通过CSS添加动画,都可以触发视觉上的变化。
|
||||
|
||||
(2)Style:浏览器对样式进行计算。匹配选择器,计算哪些CSS受到了影响。
|
||||
|
||||
(3)layout:同上一段。
|
||||
|
||||
(4)painting:同上一段。
|
||||
|
||||
(5)conmposite:同上一段。
|
||||
|
||||
理论上,上面的五个步骤都是必须要经历的。布局和绘制是关键渲染路径中,最重要、开销最高的两个步骤。
|
||||
|
||||
但是,有些样式并不会影响布局,也不会影响绘制。所以,浏览器对这方面的性能进行了优化,并不一定要经历布局和绘制这两个过程。这就需要我们先了解一下「重排」和「重绘」这两个概念。详见下一段。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 布局/回流/重排
|
||||
|
||||
### 定义
|
||||
|
||||
布局 layout:
|
||||
|
||||
渲染对象在创建完成并添加到渲染树时,是将DOM节点和它对应的样式结合起来,并不包含位置和大小信息。
|
||||
|
||||
我们还需要通过 `Layout` 布局阶段,来计算它们在设备视口(viewport)内的确切位置和大小,计算这些值的过程称为`回流`、`布局`或`重排(Reflow)`。
|
||||
|
||||
|
||||
|
||||
参考链接:
|
||||
|
||||
- [从浏览器渲染原理,浅谈回流重绘与性能优化](https://www.cnblogs.com/xiahj/p/11777786.html)
|
||||
|
||||
- [你真的了解回流和重绘吗](https://github.com/chenjigeng/blog/issues/4)
|
||||
|
||||
### 什么时候会触发布局
|
||||
|
||||
DOM元素的**大小**和**位置**发生变化的时候,会触发布局。
|
||||
|
||||
- 增加、删除DOM元素
|
||||
|
||||
- display: none
|
||||
|
||||
- 移动元素位置,或是增加动画
|
||||
|
||||
- 修改CSS样式时(宽高、display 为none等,都是通过css样式来修改的)
|
||||
|
||||
- offsetLeft、scrollTop、clientWidth
|
||||
|
||||
- 修改浏览器窗口大小时(即Resize窗口,移动端没有这个问题),或是滚动的时候,**有可能**会触发(具体要看浏览器的规则)。
|
||||
|
||||
- 修改网页的默认字体时(这个很消耗性能)。
|
||||
|
||||
**面试总结:**
|
||||
|
||||
首先要答出 Reflow 定义;其次,什么时候触发,至少要答出两条。更进一步,面试官可能还会问你**怎么避免reflow**,这个可以自己去查查。
|
||||
|
||||
|
||||
|
||||
## 绘制/重绘
|
||||
|
||||
### 定义
|
||||
|
||||
**绘制 paint**:当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器便把这些元素都按照各自的特性绘制一遍,于是页面的内容出现了,这个过程也称之为 Repaint(重绘制)。
|
||||
|
||||
说白了,页面要呈现的内容,统统画在屏幕上,这就叫 Repaint。
|
||||
|
||||
### 什么时候触发绘制
|
||||
|
||||
- DOM改动
|
||||
|
||||
- CSS改动
|
||||
|
||||
其实,就是判断当视觉上是否发生变化(无论这个变化是通过DOM改动还是CSS改动)。只要页面显示的内容不一样了,肯定要 Repaint。
|
||||
|
||||
**面试总结:**
|
||||
|
||||
面试官经常会问:“如何**尽量减少**Repaint的频率?”
|
||||
|
||||
注意, reflow是问“怎么避免”,repaint是问“怎么减少”。Repaint是无法避免的,否则就成了静态页面了。
|
||||
|
||||
**答案**:
|
||||
|
||||
(1)如果需要创建多个DOM节点,可以使用**DocumentFragment**创建完,然后一次性地加入document。(加一个节点,就repaint一次,不太好)
|
||||
|
||||
(2)将元素的display设置为”none”,完成修改后再把display修改为原来的值。
|
||||
|
||||
参考链接:[如何减少浏览器repaint和reflow ?](http://blog.csdn.net/liaozhongping/article/details/47057889)
|
||||
|
||||
|
||||
169
13-前端性能优化/03-渲染优化.md
Normal file
169
13-前端性能优化/03-渲染优化.md
Normal file
@@ -0,0 +1,169 @@
|
||||
|
||||
|
||||
## 浏览器的渲染机制
|
||||
|
||||
我们需要先理解浏览器的渲染经历了哪些过程,才能有针对性的进行相关优化。
|
||||
|
||||
掌握浏览器的渲染优化,可以说是前端工程师的一个分水岭。如果想要具备架构师的思维,需要达到什么样的能力?不光是要解决当下的问题,还需要掌握基本的原理,将来在遇到新问题时也能解决,即“预测问题”。
|
||||
|
||||
有一个经典的面试题是:“在浏览器的地址栏输入url,回车后,经历了哪些过程?”这个问题并不简单,根据你回答的详细程度,可以看出你对前后端知识的掌握程度。你能否答出“浏览器的渲染机制”?如果不能,说明你对浏览器渲染的性能优化,不够了解。
|
||||
|
||||
关于浏览器的渲染机制,可以看本教程的另外一篇文章:
|
||||
|
||||
> 《前端面试/面试必看/浏览器渲染机制.md》
|
||||
|
||||
|
||||
|
||||
关键渲染路径举例:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 避免布局抖动(layout thrashing)
|
||||
|
||||
1、尽量避免 重排:
|
||||
|
||||
比如说,如果想改变一个元素的位置,很多人可能会使用相对布局的left、top属性,但是这个属性会引起重排。我们可以使用 `transfrom:translate`让元素做位移,这个属性既不会触发重排,也不会触发 重绘,只会触发 conmposite。
|
||||
|
||||
再比如说,vue、react这样的框架,采用了虚拟DOM,它会把涉及到DOM修改的操作积攒起来,然后统一计算,批量处理,最后应用到真正的DOM上。
|
||||
|
||||
2、读写分离。建议先批量读(获取位置等信息),然后再批量做写操作(修改位置)。
|
||||
|
||||
补充:
|
||||
|
||||
如果你的页面经常需要做重排、重绘,就很容易导致“页面抖动”。
|
||||
|
||||
很多时候,我们知道原理和解决方案。但是在工程化实践的时候,往往时间很紧,没有时间去做这些事情。我们希望有一些拿来就可以用的、而且经过测试没有问题的工具,来帮我们解决问题。
|
||||
|
||||
FastDom是用于做防抖的一个比较流行的解决方案。
|
||||
|
||||
|
||||
|
||||
## 减少重绘(repaint)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 防抖(Debounce):降低事件的触发频率
|
||||
|
||||
我们可以针对**高频事件**做防抖。
|
||||
|
||||
**高频事件处理函数**:有很多事件的触发频率非常高,甚至超过了屏幕的刷新率(60帧/秒)。比如页面滚动、鼠标移动、移动端的touch事件。
|
||||
|
||||
如果我们不对这些事件做处理,就会频繁导致浏览器做重排、重绘,影响性能,导致页面卡顿,也就是“抖动”。因此需要对这些高频事件处理函数做防抖处理,降低它们的触发频率。
|
||||
|
||||
比如说滚动事件:我其实并不关心滚动中间的过程,我只关心最终滚动到了哪里。
|
||||
|
||||
requestAnimationFrame 这个api可以做防抖。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
参考文章:
|
||||
|
||||
- 防抖与节流:https://juejin.cn/post/6885250789825052679
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 代码优化
|
||||
|
||||
|
||||
|
||||
### JS的开销
|
||||
|
||||
静态资源有很多种:js、图片、css、字体等。这些资源都有可能会很大,但是JS的开销仍然是最昂贵的,因为JS除了加载资源之外,还需要经历**解析&编译**、**执行的**过程。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 如何缩短JS的解析事件
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Web loading is a Journey
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### V8引擎
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 补充
|
||||
|
||||
|
||||
|
||||
- 首屏尽快打开,剩下的内容延迟加载,减少初次加载的资源量。首屏的内容是可以确定的。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
39
13-前端性能优化/lazyload&防抖动和节流阀.md
Normal file
39
13-前端性能优化/lazyload&防抖动和节流阀.md
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
|
||||
|
||||
## lazyload
|
||||
|
||||
用的最多的场景是:
|
||||
|
||||
- 图片lazyload
|
||||
|
||||
- 组件lazyload
|
||||
|
||||
现在一般都单独做css的lazyload或者js的lazyload,因为这种方式,其实还是要加载图片和组件。
|
||||
|
||||
|
||||
|
||||
### 图片lazyload
|
||||
|
||||
图片一般是页面最大的资源,所以**非首屏**延迟加载很重要(让首屏尽快显示)。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 防抖动(Debouncing)和节流阀(Throtting)
|
||||
|
||||
|
||||
|
||||
|
||||
参考链接:
|
||||
|
||||
- [实例解析防抖动(Debouncing)和节流阀(Throttling)](http://www.css88.com/archives/7010)
|
||||
|
||||
|
||||
593
13-前端性能优化/静态资源优化.md
Normal file
593
13-前端性能优化/静态资源优化.md
Normal file
@@ -0,0 +1,593 @@
|
||||
## 图片格式和应用场景
|
||||
|
||||
### JPEG 格式
|
||||
|
||||
JPEG(Joint Photographic Experts Group)是一种针对彩色照片而广泛使用的有损压缩图形格式,属于位图。
|
||||
|
||||
常用文件扩展名为`.jpg`,也有 `.jpeg`和`.jpe`。JPEG 在互联网上常被应用于存储和传输照片。
|
||||
|
||||
- 适合:颜色丰富的照片、彩色图大焦点图、通栏 banner 图;结构不规则的图形。
|
||||
|
||||
- 不适合:线条图形和文字、图标图形,因为它的压缩算法不太这些类型的图形;并且不支持透明度。
|
||||
|
||||
### PNG 格式
|
||||
|
||||
PNG(Portable Network Graphics)是一种无损压缩的位图图形格式,支持索引、灰度、RGB 三种颜色方案以及 Alpha 通道等特性。
|
||||
|
||||
PNG 最初是作为替代 GIF 来设计的,能够显示 256 色,文件比 JPEG 或者 GIF 大,但是 PNG 非常好的保留了图像质量。支持 Alpha 通道的半透明和透明特性。最高支持 24 位彩色图像(PNG-24)和 8 位灰度图像(PNG-8)。
|
||||
|
||||
- 适合:纯色、**透明**、线条绘图,图标;边缘清晰、有大块相同颜色区域;需要带**半透明**的图片。
|
||||
|
||||
- 适合:由于是无损存储,所以不太适合体积太大的彩色图像
|
||||
|
||||
|
||||
比如说,如果你需要带透明背景的图片,此时就可以用 png 格式的图。
|
||||
|
||||
### GIF 格式
|
||||
|
||||
GIF(Graphics Interchange Format)是一种位图图形格式,以 8 位色(即 256 种颜色)重现真彩色的图像,采用 LZW 压缩算法进行编码。
|
||||
|
||||
支持 256 色;仅支持完全透明和完全不透明;如果需要带动画效果的图片,GIF 是比较通用的选择。
|
||||
|
||||
- 适合:动画,图标。
|
||||
|
||||
- 不适合:每个像素只有 8 比特,不适合存储彩色图片。
|
||||
|
||||
### Webp 格式
|
||||
|
||||
Webp 是一种现代图像格式,可为图像提供无损压缩和有损压缩,这使得它非常灵活。由 Google 在购买 On2 Technologies 后发展出来,以 BSD 授权条款发布。
|
||||
|
||||
Webp的优秀算法能同时保证图像质量和较小体积;可以插入多帧,实现动画效果;可以设置透明度;采用 8 位压缩算法。
|
||||
|
||||
无损的 Webp 比 PNG 小 26%,有损的 Webp 比 JPEG 小 25-34%,比 GIF 有更好的动画。
|
||||
|
||||
- 适合:适用于图形和半透明图像。
|
||||
|
||||
|
||||
### 总结
|
||||
|
||||
- banner图、大图,可以用 jpg、webp格式。
|
||||
|
||||
- 图标、带透明背景的图,可以用 png 格式。
|
||||
|
||||
- 带动画效果的图,可以用 gif 格式。
|
||||
|
||||
|
||||
## 图片优化的常见方法
|
||||
|
||||
### 1、用工具压缩图片
|
||||
|
||||
**压缩 PNG 图片**:
|
||||
|
||||
- 工具:[node-pngquant-native](https://www.npmjs.com/package/node-pngquant-native)
|
||||
|
||||
- 介绍:跨平台、压缩比特别高,压缩png24非常好。
|
||||
|
||||
安装方法:
|
||||
|
||||
```
|
||||
npm install node-pngquant-native
|
||||
```
|
||||
|
||||
**压缩 JPEG 图片**:
|
||||
|
||||
- 工具:[jpegtran](https://www.npmjs.com/package/jpegtran)
|
||||
|
||||
- 官网:<https://www.npmjs.com/package/jpegtran>
|
||||
|
||||
- 介绍:跨平台,但压缩的比率只有80-90%。
|
||||
|
||||
安装方法:
|
||||
|
||||
```bash
|
||||
npm install –g jpegtran
|
||||
```
|
||||
|
||||
使用方法:
|
||||
|
||||
```bash
|
||||
jpegtran -copy none -optimize -outfile output_file.jpg input_file.jpg
|
||||
```
|
||||
|
||||
**压缩 GIF 图**:
|
||||
|
||||
- 工具:Gifsicle
|
||||
|
||||
- 官网(含安装方法):<https://www.lcdf.org/gifsicle/>
|
||||
|
||||
- 介绍:Gifsicle 通过改变每帧比例,减小 gif文件大小,同时可以使用透明来达到更小的文件大小,是目前公认的最好的解决方案。
|
||||
|
||||
使用方法:
|
||||
|
||||
```bash
|
||||
# 压缩命令。注意,这里是将压缩级别设置为3。如果将压缩级别设置为1或者2,则基本不压缩。
|
||||
gifsicle --optimize=3 -o out_file.gif in_file.gif
|
||||
|
||||
# 裁掉透明部分
|
||||
gifsicle --optimize=3 --crop-transparency -o out_file.gif in_file.gif
|
||||
```
|
||||
|
||||
### 2、将图片尺寸跟随网络环境进行变化
|
||||
|
||||
**具体方案**:不同网络环境(Wifi/4G/3G)下,加载不同尺寸和像素的图片,通过在图片 URL 中添加参数来改变。
|
||||
|
||||
图片 url 举例1:(图片的原始url链接)
|
||||
|
||||
```
|
||||
https://img12.360buyimg.com/img/s3866x3866_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
|
||||
```
|
||||
|
||||
图片 url 举例2:(通过图片的url参数,将这张图的尺寸设置为200px)
|
||||
|
||||
```
|
||||
https://img12.360buyimg.com/img/s200x200_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
|
||||
```
|
||||
|
||||
### 3、响应式图片
|
||||
|
||||
**方法1**:通过 JavaScript 绑定事件,检测窗口大小,以此设置图片大小。
|
||||
|
||||
|
||||
**方法2**:CSS媒体查询。
|
||||
|
||||
代码举例:(在 640px的窗口大小里,设置图片的尺寸为640px)
|
||||
|
||||
```css
|
||||
@media screen and (max-width:640px) {
|
||||
my_image{
|
||||
width:640px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**方法3**:img标签的 `srcset` 属性。这个是 H5的新特性。
|
||||
|
||||
代码举例:
|
||||
|
||||
```html
|
||||
<img srcset="img-320w.jpg, img-640w.jpg 2x, img-960w.jpg 3x" src=“img-960w.jpg”
|
||||
alt=“img”> (x 描述符:表示图像的设备像素)
|
||||
```
|
||||
|
||||
### 4、逐步加载图像:lazyload、LQIP、LQIP
|
||||
|
||||
**方法1**、使用统一占位符。俗称图片的`懒加载(lazyload)`。
|
||||
|
||||
**方法2**、使用 **LQIP** 的图片加载方式。也就是说,在大图没有完全加载出来的情况下,先这张图对应的的低质量图片进行占位。
|
||||
|
||||
LQIP(Low Quality Image Placeholders):低质量图像占位符。这种技术背后的想法是,在网络环境较差的情况下,你可以尽快向用户展示完全可用的网页,为他们提供更好的体验。即使在更好的网络连接上,这仍然为用户提供了更快的可用页面,并且改善了体验。
|
||||
|
||||
- 安装 LQIP 工具:`npm install lqip`
|
||||
|
||||
- GitHub源码:https://github.com/zouhir/lqip-loader
|
||||
|
||||
代码举例:(将目标图片转换为 LQIP 形式的图)
|
||||
|
||||
```js
|
||||
const lqip = require('lqip');
|
||||
|
||||
//文件路径
|
||||
const file = './in.png';
|
||||
|
||||
//将输入的图片转为base64
|
||||
lqip.base64(file).then(res => {
|
||||
// 色值
|
||||
console.log(res);
|
||||
});
|
||||
|
||||
lqip.palette(file).then(res => {
|
||||
//这里输出的是base64的图片地址
|
||||
console.log(res);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
另外,我们还可以使用 **SQIP** 的图片加载方式。
|
||||
|
||||
SQIP(SVG Quality Image Placeholders): SVG 格式的图像占位符。
|
||||
|
||||
- 安装 SQIP 工具:`npm install sqip`
|
||||
|
||||
- GitHub 源码:<https://github.com/axe312ger/sqip>
|
||||
|
||||
代码举例:(将目标图片转换为 SQIP 形式的图)
|
||||
|
||||
```js
|
||||
const sqip = require('sqip');
|
||||
|
||||
const result = sqip({
|
||||
filename: './input_file.png',
|
||||
numberOfPrimitives: 10 //可根据不同应用场景设置大小
|
||||
});
|
||||
|
||||
console.log(result.final_svg);
|
||||
```
|
||||
|
||||
### 5、雪碧图(Image spriting)
|
||||
|
||||
雪碧图是比较常见的图片优化方式,也就是把多张小图合并成一张大图。这样的话,就只需做一次网络请求,减少图片的 http 请求次数。
|
||||
|
||||
读者们可以自行查阅。
|
||||
|
||||
### 6、有些场景下,并不需要图片文件
|
||||
|
||||
有些场景下,并不需要图片,我们可以用其他的方式来代替图片。
|
||||
|
||||
举例:
|
||||
|
||||
- Web Font 代替图片
|
||||
|
||||
- 使用 Data URI 代替图片。base64就是属于 Data URI的方式。
|
||||
|
||||
### 7、在服务器端进行图片自动优化
|
||||
|
||||
|
||||
图片服务器自动化优化是可以在图片 URL 链接上增加不同特殊参数,服务器自动化生成。通过这些参数,可以设置图片的不同格式、大小、质量。
|
||||
|
||||
**常见处理方式**:
|
||||
|
||||
- 图片裁剪:按长边、短边、填充、拉伸等缩放。
|
||||
|
||||
- 图片格式转换:支持 JPG,GIF,PNG,WebP 等,支持不同的图片压缩率。
|
||||
|
||||
- 图片处理:添加图片水印、高斯模糊、重心处理、裁剪边框等。
|
||||
|
||||
- AI 能力:鉴黄、涉政、智能抠图、智能排版、智能配色、智能合成等 AI 功能。
|
||||
|
||||
**图片举例**:
|
||||
|
||||
比如JD公司的图片链接,就会在服务器端做优化处理。通过修改图片链接中的参数,就能自动达到相应的优化效果。
|
||||
|
||||
原始图片链接:
|
||||
|
||||
```
|
||||
https://img12.360buyimg.com/img/s3866x3866_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
|
||||
```
|
||||
|
||||
将图片压缩为 200*150:
|
||||
|
||||
```
|
||||
https://img12.360buyimg.com/img/s200x200_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
|
||||
```
|
||||
|
||||
将图片转换为 webp 格式:
|
||||
|
||||
```
|
||||
https://img12.360buyimg.com/img/s200x200_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.webp
|
||||
```
|
||||
|
||||
将图片质量压缩至10%:
|
||||
|
||||
```
|
||||
https://img12.360buyimg.com/img/s3866x3866_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg.q10
|
||||
```
|
||||
|
||||
|
||||
## HTML优化
|
||||
|
||||
### 1、精简 HTML 代码
|
||||
|
||||
- 减少 HTML 的嵌套。
|
||||
|
||||
- 减少 DOM 节点数。
|
||||
|
||||
- 减少无语义代码(比如: <div class=“clear”></div> 消除浮动,其实可以用css来处理)。
|
||||
|
||||
- 删除 http 或者 https:如果URL的协议头和当前页面的协议头一致的,或者此 URL 在多个协议头都是可用的,则可以考虑删除协议头。
|
||||
|
||||
- 删除多余的空格、换行符、缩进和不必要的注释。
|
||||
|
||||
- 省略冗余标签和属性。
|
||||
|
||||
- 使用相对路径的 URL。
|
||||
|
||||
### 2、文件放在合适位置
|
||||
|
||||
- CSS 样式文件链接尽量放在页面头部。
|
||||
|
||||
CSS 加载不会阻塞 DOM tree 解析,但是会阻塞 DOM Tree 渲染,也会阻塞后面 JS 执行。
|
||||
|
||||
任何 body 元素之前,可以确保在文档部分中解析了所有 CSS 样式(内联和外联),从而减少了浏览器必须重排文档的次数。
|
||||
|
||||
如果放置页面底部,就要等待最后一个 CSS 文件下载完成,此时会出现"白屏",影响用户体验。
|
||||
|
||||
- JS 引用放在 HTML 底部
|
||||
|
||||
防止 JS 在加载、解析、执行时,阻塞了页面后续元素的正常渲染。
|
||||
|
||||
### 4、增强用户体验
|
||||
|
||||
- 设置 favicon.ico
|
||||
|
||||
网站如果不设置 favicon.ico,控制台会报错。另外页面加载过程中如果没有图标,则会出现 loading 过程,也不利于记忆网站品牌,建议统一添加。
|
||||
|
||||
- 增加首屏必要的 CSS 和 JS
|
||||
|
||||
页面如果需要等待所的依赖的 JS 和 CSS 加载完成才显示,则在渲染过程中页面会一直显示空白,影响用户体验,建议在首屏增加必要的 CSS 和 JS,比如页面框架背景图片或者loading 图标,内联在 HTML 页面中。这样做,首屏能快速显示出来,缓解用户焦虑。现在很多网页在初始化的时候,流行做**骨架屏**,小伙伴们也可以研究下。
|
||||
|
||||
## CSS优化
|
||||
### 1、提升 CSS 渲染性能
|
||||
|
||||
- 谨慎使用 expensive 属性,这类属性比较耗浏览器的性能。比如:`nth-child` 伪类;`position: fixed` 定位。
|
||||
|
||||
- 尽量减少样式的层级数。
|
||||
|
||||
比如:`div ul li span i {color: blue;}`这样的层级就太深了。建议给 i 标签设置 class属性,然后通过class直接设置样式属性,可以提升浏览器的查询效率。
|
||||
|
||||
- 尽量避免使用占用过多 CPU 和内存的属性。比如:`text-indnt:-99999px`。
|
||||
|
||||
- 尽量少使用耗电量大的属性。比如:CSS3 3D transforms、CSS3 transitions、Opacity 这样的属性会消耗GPU。
|
||||
|
||||
### 2、合适使用 CSS 选择器
|
||||
|
||||
- 尽量避免使用 CSS 表达式。
|
||||
|
||||
比如 `background-color: expression( (new Date()).getHours()%2 ? "#FFF" : "#000" );`这个属性的意思是,每间隔两小时,改变白景色。
|
||||
|
||||
- 尽量避免使用通配选择器。
|
||||
|
||||
比如 `body > a {font-weight:blod;}`这样的属性,可能会把 body 里所有的标签遍历一遍,才找到 a 标签,比较耗时。
|
||||
|
||||
- 尽量避免类正则的属性选择器:`*=, |=, ^=, $=`
|
||||
|
||||
### 3、提升 CSS 文件加载性能
|
||||
|
||||
- 使用外链的 CSS。
|
||||
|
||||
我们知道,内联的 css 是在html 内部写的。相比之下,外链的 CSS文件是放在CDN上的,可以缓存,既能减少 html 页面的体积大小,也能利用缓存减少资源的请求。
|
||||
|
||||
- 尽量避免使用 @import 方法
|
||||
|
||||
整个CSS加载完成后,浏览器会把 import 中所有依赖的文件全部加载完成后,浏览器才会接着往下渲染。这个过程会阻塞CSS文件的加载过程。
|
||||
|
||||
### 4、精简 CSS 代码
|
||||
|
||||
- 使用缩写语句
|
||||
|
||||
- 删除不必要的零。比如 0.2 可以写成 .2
|
||||
|
||||
- 删除不必要的单位,比如 0px 可以写成 0
|
||||
|
||||
- 删除过多的空格;注释言简意赅
|
||||
|
||||
- 尽量减少样式表的大小
|
||||
|
||||
当然,很多地方可以在编译时,通过压缩工具来处理;但是我们在写代码时,也应该有良好的编码习惯。
|
||||
### 5、合理使用 Web Fonts
|
||||
|
||||
- 将字体文件部署在 CDN 上。
|
||||
|
||||
- 或者将字体以 base64 形式保存在 CSS 中并通过 localStorage 进行缓存
|
||||
|
||||
- Google 字体库因为某些不可抗拒原因,应该使用国内托管服务
|
||||
|
||||
### 6、CSS 动画优化
|
||||
|
||||
- 尽量避免同时出现过多动画。
|
||||
|
||||
- 延迟动画初始化:让其他的重要的CSS样式优先渲染。
|
||||
|
||||
- 结合 SVG。
|
||||
|
||||
|
||||
## JavaScript 总体优化
|
||||
|
||||
### 提升 JavaScript 文件加载性能
|
||||
|
||||
加载元素的顺序 CSS 文件放在 <head> 里, JavaScript 文件放在 <body> 里。
|
||||
|
||||
### JavaScript 变量和函数优化
|
||||
|
||||
- 尽量使用 id 选择器
|
||||
|
||||
- 尽量避免使用 eval
|
||||
|
||||
- JavaScript 函数尽可能保持简洁
|
||||
|
||||
- 使用事件节流函数
|
||||
|
||||
- 使用事件委托
|
||||
|
||||
### JavaScript 动画优化
|
||||
|
||||
- 避免添加大量 JavaScript 动画
|
||||
|
||||
- 尽量使用 CSS3 动画
|
||||
|
||||
- 尽量使用 Canvas 动画
|
||||
|
||||
- 合理使用 requestAnimationFrame 动画代替 setTimeout、setInterval
|
||||
|
||||
- requestAnimationFrame可以在正确的时间进行渲染,setTimeout(callback)和setInterval(callback)无法保证 callback 回调函数的执行时机。
|
||||
|
||||
### 合理使用缓存
|
||||
|
||||
- 合理缓存 DOM 对象
|
||||
|
||||
- 缓存列表长度
|
||||
|
||||
- 使用可缓存的 Ajax
|
||||
|
||||
## JavaScript 缓存优化
|
||||
|
||||
### Cookie
|
||||
|
||||
通常由浏览器存储,然后将 Cookie 与每个后续请求一起发送到同一服务器。收到HTTP 请求时,服务器可以发送带有 Cookie 的 header 头。可以给 Cookie 设置有效时间。
|
||||
|
||||
应用:
|
||||
|
||||
- 会话管理:登录名,购物车商品,游戏得分或服务器应要记录的其他任何内容
|
||||
|
||||
- 个性化:用户首选项,主题或其他设置
|
||||
|
||||
- 跟踪:记录和分析用户行为,比如visitkey
|
||||
|
||||
### sessionStorage
|
||||
|
||||
创建一个本地存储的键/值对。
|
||||
|
||||
应用:
|
||||
|
||||
- 缓存。
|
||||
|
||||
- 页面应用页面之间传值。
|
||||
|
||||
### LocalStorage
|
||||
|
||||
本地存储。
|
||||
|
||||
应用于:
|
||||
|
||||
- 缓存静态文件内容 JavaScript /CSS(比如百度M站首页)
|
||||
|
||||
- 缓存不常变更的 API 接口数据
|
||||
|
||||
- 储存地理位置信息
|
||||
|
||||
- 浏览在页面的具体位置
|
||||
|
||||
### IndexedDB
|
||||
|
||||
索引数据库。
|
||||
|
||||
应用:
|
||||
|
||||
- 客户端存储大量结构化数据
|
||||
|
||||
- 没有网络连接的情况下使用(比如 Google Doc、石墨文档)
|
||||
|
||||
- 将冗余、很少修改、但经常访问的数据,以避免随时从服务器获取数据
|
||||
|
||||
## JavaScript 模块化加载方案和选型
|
||||
|
||||
- CommonJS
|
||||
|
||||
旨在 Web 浏览器之外为 JavaScript 建立模块生态系统。Node.js 模块化方案受 CommonJS。
|
||||
|
||||
|
||||
- AMD (Asynchronous Module Definition)(异步模块定义)规范。
|
||||
|
||||
RequireJS 模块化加载器:基于 AMD API 实现。
|
||||
|
||||
- CMD( Common Module Definition)(通用模块定义)规范。
|
||||
|
||||
SeaJS 模块化加载器:遵循 CMD API 编写。
|
||||
|
||||
- ES6 import。
|
||||
|
||||
## 减少回流和重绘重要举措
|
||||
|
||||
### CSS
|
||||
|
||||
- 避免过多样式嵌套
|
||||
|
||||
- 避免使用 CSS 表达式
|
||||
|
||||
- 使用绝对定位,可以让动画元素脱离文档流
|
||||
|
||||
- 避免使用 table 布局
|
||||
|
||||
- 尽量不使用 float 布局
|
||||
|
||||
- 图片最好设置好 width 和 height
|
||||
|
||||
- 尽量简化浏览器不必要的任务,减少页面重新布局
|
||||
|
||||
- 使用 Viewport 设置屏幕缩放级别
|
||||
|
||||
- 避免频繁设置样式,最好把新 style 属性设置完成后,进行一次性更改
|
||||
|
||||
- 避免使用引起回流/重绘的属性,最好把相应变量缓存起来
|
||||
|
||||
### JavaScript
|
||||
|
||||
- 最小化回流和重排:为了减少回流发生次数,避免频繁或操作 DOM,可以合并多次对 DOM 修改,然后一次性批量处理。
|
||||
|
||||
- 控制绘制过程和绘制区域:绘制过程开销比较大的属性设置应该尽量避免减少使用;同时,减少绘制区域范围。
|
||||
|
||||
|
||||
## DOM 编程优化的⽅式方法
|
||||
|
||||
### 控制 DOM 大小
|
||||
|
||||
众所周知,页面交互卡顿和流畅度很大一部分原因就是页面有大量 DOM 元素。想象一下,从一个上万节点的 DOM 树上,使用 querySelectorAll 或 getElementByTagName 方法查找某一个节点,是非常耗时的。另外元素绑定事件,事件冒泡和事件捕获的执行也会相对耗时。
|
||||
|
||||
通常控制 DOM 大小的技巧包括:
|
||||
|
||||
- 合理的业务逻辑
|
||||
|
||||
- 延迟加载即将呈现的内容
|
||||
|
||||
### 简化 DOM 操作
|
||||
|
||||
对DOM节点的操作统一处理后,再统一插入到 DOM Tree中。
|
||||
|
||||
可以使用 fragment,尽量不在页面 DOM Tree 里直接操作。
|
||||
|
||||
现在流行的框架 Angular、React、Vue 都在使用虚拟 DOM 技术,通过 diff 算法简化和减少 DOM 操作。
|
||||
|
||||
|
||||
## 静态文件压缩工具介绍
|
||||
|
||||
HTML 压缩工具:
|
||||
|
||||
- html-minifier:https://www.npmjs.com/package/html-minifier
|
||||
|
||||
|
||||
CSS 压缩工具:
|
||||
|
||||
- clean-css:https://www.npmjs.com/package/clean-css
|
||||
|
||||
JavaScript 压缩工具:
|
||||
|
||||
- uglify-js:https://www.npmjs.com/package/uglify-js
|
||||
|
||||
- 使用方法:uglifyjs in.js -o out.js
|
||||
|
||||
## 静态⽂文件打包⽅方案
|
||||
|
||||
- 公共组件拆分
|
||||
|
||||
- 压缩: JavaScript /CSS/图片
|
||||
|
||||
- 合并: JavaScript /CSS 文件合并,CSS Sprite
|
||||
|
||||
- Combo: JavaScript /CSS 文件
|
||||
|
||||
## 静态⽂文件版本号更新策略
|
||||
|
||||
缓存更新:CDN 或 ng 后台刷新文件路径,更新文件header头。
|
||||
|
||||
文件 name.v1-v100.js:
|
||||
|
||||
- 大功能迭代每次新增一个大版本,比如由 v1 到 v2
|
||||
|
||||
- 小功能迭代新增加 0.0.1 或者 0.1.0,比如从 v1.0.0 至 v1.0.1
|
||||
|
||||
- 年末 ng 统一配置所有版本 302 至最新版
|
||||
|
||||
时间戳.文件 name.js:以每次上线时间点做差异。
|
||||
|
||||
hash.文件。以文件内容 hash 值做 key。
|
||||
|
||||
## 前端构建工具介绍和选型建议
|
||||
|
||||
### 常用构建工具
|
||||
|
||||
- Gulp:通过流(Stream)来简化多个任务间的配置和输出,配置代码相对较少。
|
||||
|
||||
- Webpack:预编译,中间文件在内存中处理,支持多种模块化,配置相对很简单。
|
||||
|
||||
- FIS
|
||||
|
||||
|
||||
### webpack 打包优化
|
||||
|
||||
- 定位体积大的模块
|
||||
|
||||
- 删除没有使用的依赖
|
||||
|
||||
- 生产模式进行公共依赖包抽离
|
||||
|
||||
- 开发模式进行 DLL & DllReference 方式优化
|
||||
|
||||
369
13-前端性能优化/页面渲染性能优化.md
Normal file
369
13-前端性能优化/页面渲染性能优化.md
Normal file
@@ -0,0 +1,369 @@
|
||||
## 浏览器渲染过程
|
||||
|
||||

|
||||
|
||||
1. 浏览器解析 HTML,生成 DOM Tree(Parse HTML)。
|
||||
|
||||
2. 浏览器解析 CSS,生成 CSSOM(CSS Object Model)Tree。
|
||||
|
||||
3. JavaScript 会通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree,浏览器将 DOM Tree 和 CSSOM Tree 合成渲染树(Render Tree)。
|
||||
|
||||
4. 布局(Layout):根据生成的 Render Tree,进行回流,以计算每个节点的几何信息(位置、大小、字体样式等等)。
|
||||
|
||||
5. 绘制(Painting):根据渲染树和回流得到的几何信息,得到每个节点的绝对像素。
|
||||
|
||||
6. 展示(Display):将像素发送给图形处理器(GPU),展示在页面上。
|
||||
|
||||
## 页面渲染技术方案总览
|
||||
|
||||
**服务端渲染**:
|
||||
|
||||
- 后端同步渲染、同构直出、BigPipe。
|
||||
|
||||
**客户端渲染**:
|
||||
|
||||
- JavaScript 渲染:静态化、前后端分离、单页面应用
|
||||
|
||||
- Web App:React、Vue、PWA
|
||||
|
||||
- Hybrid App:PhoneGap 、AppCan 等
|
||||
|
||||
- 跨平台开发:RN 、Flutter 、小程序等。
|
||||
|
||||
- 原生 App:iOS 、Android
|
||||
|
||||
建议:
|
||||
|
||||
- 依赖业务形式、依赖团队规模、依赖技术水平。
|
||||
|
||||
## 静态化技术方案
|
||||
|
||||
静态化是使动态化的网站生成静态 HTML 页面以供用户更好访问的技术,一般分为纯动态化和伪动态化。
|
||||
|
||||
技术优势:
|
||||
|
||||
- 提高了页面访问速度,降低了服务器的负担,因为访问页面时不需要每次去访问数据库。
|
||||
|
||||
- 提高网站内容被搜索引擎搜索到的几率,因为搜索引擎更喜欢静态页面。
|
||||
|
||||
- 网站更稳定,如果后端程序、数据库出现问题,会直接影响网站的正常访问,而静态化页面有缓存,更不容易出现问题。
|
||||
|
||||
技术不足:
|
||||
|
||||
- 服务器存储占用问题,因为页面量级在增加,要占用大量硬盘空间。
|
||||
|
||||
- 静态页面中的链接更新问题会有死链或者错误链接问题。
|
||||
|
||||
技术实现:
|
||||
|
||||
- 跑定时任务,将已有的动态内容进行重定,生成静态的 HTML 页面。
|
||||
|
||||
- 利用模板技术,将模板引擎中模板字符替换为从数据库字段中取出来的值, 同时生成 HTML 文件。
|
||||
|
||||
协作方式:
|
||||
|
||||
- 前端统一写好带有交互的完整静态页面。
|
||||
|
||||
- 后端拆分出静态页面文件,并嵌套在后端模板文件中。
|
||||
|
||||
选型建议:后端研发人员充分,又需要考虑用户体验、服务器负载的业务。
|
||||
|
||||
## 前后端分离技术与实现
|
||||
|
||||
前后端分离是指研发人员分离、业务代码分离、后端实现业务接口,前端渲染页面。
|
||||
|
||||
技术实现:
|
||||
|
||||
- 后端只负责功能接口实现,提供按照约定的数据格式并封装好的 API 接口。
|
||||
|
||||
- 前端负责业务具体实现,获取到 API 接口数据后,进行页面模板拼接和渲染,独立上线。
|
||||
|
||||
协作方式:
|
||||
|
||||
- 前端负责实现页面前端交互,根据后端 API 接口拼装前端模板。
|
||||
|
||||
- 后端专注于业务功能实现和 API 接口封装。
|
||||
|
||||
技术优势:
|
||||
|
||||
- 团队更加专注
|
||||
|
||||
- 提升了开发效率
|
||||
|
||||
- 增加代码可维护性
|
||||
|
||||
技术架构:
|
||||
|
||||
- 后端架构:Java、C++、PHP、 + Nginx,使用微服务(比如 Dubbo 等)等实现业务的解耦,所有的服务使用某种协议提供不同的服务(比如 JSF 等) 。
|
||||
|
||||
- 前端架构:使用 Angular、React、Vue 前端框架并部署页面至 CDN。
|
||||
|
||||
- 前端架构 2:使用 Angular、React、Vue 前端框架并部署在 Node Server。
|
||||
|
||||
技术不足:
|
||||
|
||||
- 因为前端需要负责一大部分业务逻辑实现,和服务端同步、静态化,需要前端人力非常多。
|
||||
|
||||
- 页面数据异步渲染,不利于 SEO,搜索引擎更喜欢纯静态页面。
|
||||
|
||||
选型建议:
|
||||
|
||||
- 这是大型互联网公司正在采用的开发模式,一句话,如果考虑用户体验,以及前端人力够用,就可以积极采用。
|
||||
|
||||
## 单页面应用技术方案
|
||||
|
||||
单页应用(single-page application,缩写 SPA),通过动态重写当前页面,来与用户交互,而非传统的从服务器重新加载整个新页面。这种方法在使用过程中不需要重新加载页面,避免了页面之间切换打断用户体验,使应用程序更像一个桌面应用程序。
|
||||
|
||||
技术优点:
|
||||
|
||||
- 不错的加载速度:用户往往感觉页面加载非常快,因为一进入页面就能看到页面元素;
|
||||
|
||||
- 良好的交互体验:进行局部渲染,避免不必要的页面间跳转和重复渲染;
|
||||
|
||||
- 前后端职责分离:前端进行页面交互逻辑,后端负责业务逻辑;
|
||||
|
||||
- 减轻服务器负载:服务器只处理数据接口输出,不用考虑页面模板渲染和 HTML 展示。
|
||||
|
||||
技术缺点:
|
||||
|
||||
- 开发成本相对较高
|
||||
|
||||
- 首次页面加载时间过多
|
||||
|
||||
- SEO 难度比较大
|
||||
|
||||
技术实现:
|
||||
|
||||
- 使用 React、Vue 框架可以很好的。
|
||||
|
||||
## BigPipe 简介和工作模式
|
||||
|
||||
BigPipe 通过将页面加载到称为 Pagelet 的小部件中,来加快页面渲染速度,并允许浏览器在 PHB 服务器呈现页面的同时,一直请求页面不同区块的结构,类似一个“流”传输管道。
|
||||
|
||||
**技术实现**:
|
||||
|
||||
1. 浏览器从服务器请求页面。
|
||||
|
||||
2. Server 迅速呈现一个包含 <head> 标记的页面框架,以及一个包含空 div 元素的主体,这些元素充当 Pagelet 的容器。由于该页面尚未完成,因此与浏览器的 HTTP 连接保持打开状态。
|
||||
|
||||
3. 浏览器将开始下载 bigpipe.js 文件,然后它将开始呈现页面。
|
||||
|
||||
4. PHP 服务器进程仍在执行,并且一次构建每个 Pagelet 。Pagelet 完成后,其结果将在`<script> BigPipe.onArrive(…)</ script>` 标记内发送到浏览器。
|
||||
|
||||
5. 浏览器将收到的 html 代码注入正确的位置。如果小页面需要任何 CSS 资源,则也将下载这些 CSS 资源。
|
||||
|
||||
6. 接收完所有的页面集之后,浏览器将开始加载那些页面集所需的所有外部 JavaScript 文件。
|
||||
|
||||
7. 下载 JavaScript 后,浏览器将执行所有内联 JavaScript。
|
||||
|
||||
## 同构直出技术方案
|
||||
|
||||
一套代码既可以在服务端运行又可以在客户端运行,这就是同构(Universal)。
|
||||
|
||||
技术优势:
|
||||
|
||||
- 性能: 降低首屏渲染时间
|
||||
|
||||
- SEO: 服务端渲染对搜索引擎的爬取有着天然的优势
|
||||
|
||||
- 兼容性: 有效规避客户端兼容性问题,比如白屏
|
||||
|
||||
- 代码同构:直接上线两个版本,利于灾备。
|
||||
|
||||
技术实现:
|
||||
|
||||
- next.js:服务器端渲染 React 组件框架(参考查看:https://nextjs.org/), React 采用 ReactDOMServer 调用 renderToString() 方法。
|
||||
|
||||
- gatsbyjs:服务端 React 渲染框架(参考查看: https://www.gatsbyjs.org/)。
|
||||
|
||||
- nuxt.js:服务器端渲染 Vue 组件框架(参考查看:https://nuxtjs.org/), Vue 采用 vue-server-renderer 调用 renderToString() 方法。
|
||||
|
||||
协作方式:
|
||||
|
||||
- 后端专注于业务功能实现和 API 接口封装。
|
||||
|
||||
- 前端负责实现页面前端交互,根据后端 API 接口拼装前端模板,页面渲染,以及服务器维护。
|
||||
|
||||
选型建议:
|
||||
|
||||
- 前端要处理 Node server 的机器环境、代码部署、日志、容灾、监控等以往后端人员需要具备运维知识,前端人员的综合能力要求会比以往要高。
|
||||
|
||||
- 前端项目开发周期变长了,需要事先和产品、运营沟通排期问题。
|
||||
|
||||
## PWA 技术方案和实现思路
|
||||
|
||||
Progressive Web App,简称 PWA,PWA 应用是使用特定技术和标准模式来开发的 Web 应用,这将同时赋予它们 Web 应用和原生应用的特性。
|
||||
|
||||
技术优势:
|
||||
|
||||
- 用户可以用手机屏幕启动应用,即使在离线状态或者弱网下,通过事先缓存的资源,也可正常加载运行当前应用,可以完全消除对网络的依赖,从而给用户非常可靠的体验。
|
||||
|
||||
- 因为预先缓存了资源,部分资源无须经过网络,即秒开页面。
|
||||
|
||||
- 和移动设备上的原生应用一样,具有沉浸式的用户体验。
|
||||
|
||||
- 可以给用户发送离线推送消息。
|
||||
|
||||
技术实现:
|
||||
|
||||
- 全站改造成 HTTPS,没有 HTTPS 就没有 Service Worker。
|
||||
|
||||
- 应用 Service Worker 技术提升性能,离线提供静态资源文件,提升首屏用户体验。
|
||||
|
||||
- 使用 App Manifest。
|
||||
|
||||
- 最后可以考虑离线消息推送等功能。
|
||||
|
||||
浏览器兼容性:
|
||||
|
||||
- ServiceWorkerGlobalScope API:88%
|
||||
|
||||
- Web App Manifest 83%
|
||||
|
||||
## 页面加载策略优化
|
||||
|
||||
- 懒加载
|
||||
|
||||
- 预加载
|
||||
|
||||
- 预渲染
|
||||
|
||||
- 按需加载
|
||||
|
||||
下面具体展开讲讲。
|
||||
|
||||
### 懒加载
|
||||
|
||||
懒加载也叫延迟加载,指的是长网页中延迟加载特定元素(可以是图片,也可以是 JS/CSS 文件,当然也可以是 JavaScript 的特定函数和方法,以下简称“懒加载元素”)。
|
||||
|
||||
好处:可以减少当前屏无效资源的加载。
|
||||
|
||||
技术实现举例:把页面上“懒加载元素”src 属性设置为空字符,把真实的 src 属性写在 data-lazy 属性中,当页面滚动的时候监听 scroll 事件,如果“懒加载元素”在可视区域内,就把图片的 src 属性或者文件 URL 路径设置成 data-lazy 属性值。
|
||||
|
||||
### 预加载
|
||||
|
||||
可以使用预加载让浏览器来预先加载某些资源(比如图片、JS/CSS/模板),而这些资源是在将来才会被使用到的。简单来说,就是将所需资源提前加载到浏览器本地,这样后面在需要使用的时候就可以直接从浏览器缓存中取了,而不用再重新开始加载。
|
||||
|
||||
使用场景:如果你希望这个资源能尽快显示给用户,就可以使用预加载。
|
||||
|
||||
好处:减少用户后续加载资源等待的时间。
|
||||
|
||||
**技术实现举例**:
|
||||
|
||||
1. HTML 标签:
|
||||
|
||||
```html
|
||||
<img src="https://xxx.jpg" style="display: none" />
|
||||
```
|
||||
|
||||
2、使用 Image 对象:
|
||||
|
||||
```js
|
||||
const image = new Image();
|
||||
|
||||
image.src = 'https://xxx.jpg';
|
||||
```
|
||||
|
||||
3、使用 preload、prefetch 和 preconnect:
|
||||
|
||||
```html
|
||||
<link rel=“preload” href=“src/style.css” as=“style”>
|
||||
|
||||
<link rel="prefetch" href="scr/image.png" />
|
||||
|
||||
<link rel="dns-prefetch" href="https://my.com" />
|
||||
|
||||
<link rel="preconnect" href="https://my.com" crossorigin />
|
||||
```
|
||||
|
||||
### 预渲染
|
||||
|
||||
有一种预加载组件的方式就是提前渲染它。在页面中渲染组件,但是并不在页面中展示。也就是渲染完成后,先隐藏起来,用的时候再展示。
|
||||
|
||||
实现举例:
|
||||
|
||||
```html
|
||||
<link rel="prerender" href="https://my.com" />
|
||||
```
|
||||
|
||||
### 按需加载
|
||||
|
||||
- 常规按需加载(如 JS 原生、jQuery)
|
||||
|
||||
- 不同 App 按需加载(如 JS-SDK 脚本文件)
|
||||
|
||||
- 不同设备按需加载(如 PC 端和 HTML5 端样式文件)
|
||||
|
||||
- 不同分辨率按需加载(CSS Media Query)
|
||||
|
||||
React 异步加载举例:
|
||||
|
||||
```javascript
|
||||
const componentA = (location, callback) => {
|
||||
require.ensure(
|
||||
[],
|
||||
(require) => {
|
||||
callback(null, require('modules/componentA'));
|
||||
},
|
||||
'componentA'
|
||||
);
|
||||
};
|
||||
const componentB = (location, callback) => {
|
||||
require.ensure(
|
||||
[],
|
||||
(require) => {
|
||||
callback(null, require('modules/componentB'));
|
||||
},
|
||||
'componentB'
|
||||
);
|
||||
};
|
||||
<Router history={history}>
|
||||
<Route path="/" component={App}>
|
||||
<Route path="componentA" getComponent={componentA}></Route>
|
||||
<Route path="componentB" getComponent={componentB}></Route>
|
||||
</Route>
|
||||
</Router>;
|
||||
```
|
||||
|
||||
Vue 异步加载举例:
|
||||
|
||||
```javascript
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import VueRouter from 'vue-router';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
const componentA = resolve => require(['src/a.vue' ], resolve);
|
||||
const componentB = resolve => require(['src/b.vue' ], resolve);
|
||||
const router = new VueRouter({
|
||||
routes: [{path:"a”,name:"/a”,component:componentA},
|
||||
{path:"b”,name:"/b”,component:componentB}]
|
||||
})
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router: router,
|
||||
render: h => h(App)
|
||||
})
|
||||
```
|
||||
|
||||
## 接口服务调用优化
|
||||
|
||||
1、接口合并:一个页面的众多业务接口和依赖的第三方接口,合并为一个部署在集群的接口统一调用,以减少页面接口请求数。
|
||||
|
||||
2、接口上 CDN:主要基于接口性能考虑,我们可以把**不需要实时更新的接口同步至 CDN**,等此接口内容变更之后自动同步至 CDN 集群上。如果一定时间内未请求到数据,会用源站接口再次请求。
|
||||
|
||||
3、接口域名上 CDN:增强可用性、稳定性。
|
||||
|
||||
|
||||
4、接口降级:核心接口进行降级用基础接口进行业务实现,比如千人千面的推荐接口,在大促时间点可以直接运营编辑的数据。另外如果接口无访问,建议使用兜底数据。
|
||||
|
||||
5、接口监控:监控接口成功率,不只是常说的 TP99,也包括弱网、超时、网络异常、网络切换等一段情况的监控情况。排查出来问题后,需要联合后端、运维、网络岗位人员一并解决。
|
||||
|
||||
## 接口缓存策略优化
|
||||
|
||||
1、Ajax/fetch 缓存:前端请求时候带上 cache,依赖浏览器本身缓存机制。
|
||||
|
||||
2、本地缓存:异步接口数据优先使用本地 localStorage 中的缓存数据。
|
||||
|
||||
3、多次请求:接口数据本地无 localStorage 缓存数据,重新再次发出 ajax 请求。
|
||||
|
||||
Reference in New Issue
Block a user