update: 目录调整

This commit is contained in:
qianguyihao
2021-04-10 11:03:41 +08:00
parent 3dfab4a196
commit 1055343951
76 changed files with 214 additions and 76 deletions

View File

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

View File

@@ -0,0 +1,659 @@
## 性能指标和优化目标之加载
性能指标我们在性能优化过程中可以参考的标准这些标准都是业界或者前人总结出来的指导性经验我们可以参考这些指标去指导我们自己的优化
### 打开网站的初体验
我们以淘宝网站为例
![](http://img.smyhvae.com/20210115_1601.png)
上图中鼠标长按刷新图标松开鼠标后会弹出三个选项我们选择最后一个选项清空缓存并硬性重新加载PS只有淘宝等少数网站有这个选项其他很多网站都没有
![](https://img.smyhvae.com/20210115_1617.png)
上图中打开 chrome 调试工具点开设置icon下面的四个选项中除了Group by frame之外其他的三个选项都可以勾选上
我们可以看到淘宝网站的一些指标
- 资源量是 1.3M
- DOM加载完成时间DOMContentLoaded511ms这是一个很关键的指标
- 其他资源的总加载时间是 1.05
我们再来对比一下京东的
![](http://img.smyhvae.com/20210116-1357.png)
### 保存快照
network里的信息挺多我们可以将其保存下来留着以后做分析做对照
![](http://img.smyhvae.com/20210115-1723.png)
如上图所示我们可以在 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 文件包含了一些敏感信息
![](http://img.smyhvae.com/20210115-1733.png)
### 瀑布图 Waterfall
![](http://img.smyhvae.com/20210115_1618.png)
瀑布图可以非常直观地把网站的加载过程用自上而下的方式表达出来就像瀑布一样
瀑布图有两中解读方式一种是横向看一种是纵向看
**1横向看**
横向看的是具体的资源每一行代表某个资源的加载信息里面有一些色块来表达加载的过程每个块的颜色不同也就是说资源的下载不是单一的过程而是经历了很多环节
为了了解资源的具体加载过程我们把鼠标悬浮在第一个资源的色块上可以看见一个详情列表
![](http://img.smyhvae.com/20210115_1632.png)
1等待
- Queueing排队浏览器会对资源的请求做优先级排序
2连接
- DNS LookupDNS域名解析每个资源都有域名对域名做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
- 帧率FPSframes per second视频或者动画的内容本身每秒有多少帧由显卡输出帧率
上面的两个参数中不要把刷新率帧率弄混了刷新率是屏幕的参数帧率是图像视频等内容的参数人眼最终看到的效果是以最低的参数为准的
目前市场主流手机和电脑屏幕的刷新率基本都是60Hz即每秒显示60帧画面也就是说当我们在使用手机的时候本质上是手机在连续播放一张张静态图片每秒播放60张让肉眼误认为眼前的画面在动
![](http://img.smyhvae.com/20210107_2115.gif)
持续滑动的过程中如果页面输出到显示器的帧率低于60帧/则人眼会感觉卡顿
那么在浏览器中如何实时显示内容的 FPS 参数呢打开浏览器的控制台后按住快捷键Cmd + Shift + P然后输入 `frame`选择`Show frames per secondFPS meter`如下
![](http://img.smyhvae.com/20210115-1930.png)
![](http://img.smyhvae.com/20210115-2146.png)
**温馨提示**
2020年7月起chrome 官方已经取消了 fps参数的显示改为了 [FRS](https://twitter.com/addyosmani/status/1281483292026400768)
![](http://img.smyhvae.com/20210115-2006.png)
FRS参数观察的是丢帧率
![](http://img.smyhvae.com/20210115-2010.png)
Chrome官方给我们提供了下面这个网站用于观察 FPS 效果
- <http://googlesamples.github.io/web-fundamentals/tools/chrome-devtools/rendering-tools/forcedsync.html>
如果实在想要看fps我们可以借助第三方的 [chrome 插件]()来查看 fps参数
## RAIL 模型测量性能
RAIL 模型是Google提出的可以量化性能的测量**标准**我们做性能优化时要尽可能到这个标准
在做性能优化的时候我们需要有人告诉我们做到多好才算好有没有一些通用的标准 RAIL 模型 可以给我们带来量化的指标
**RAIL 模型包括四个方面**
![](http://img.smyhvae.com/20210115-2027.png)
- Response响应
- Animation动画
- Idle空闲时间
- load加载
参考链接
- [[Web翻译]用RAIL模型测量性能](https://juejin.cn/post/6872474167543857165)
- <https://web.dev/rail/>
**RAIL 的目标**
- 让良好的用户体验成为性能优化的目标
接下来我们再看看看 RAIL 的评估标准
### 1响应
**目标**处理用户发起的响应应该在 50ms 内完成
**准则**
- 在50毫秒内处理用户输入事件这适用于大多数输入如点击按钮切换表单控件或启动动画这不适用于触摸拖动或滚动
- 对于需要超过50毫秒才能完成的操作需要提供反馈
![](http://img.smyhvae.com/20210115-2039.png)
如上图所示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 的时候一般使用来开发调试查看 DOMcss接口请求等但其实这个工具非常强大
### size文件大小分析
![](http://img.smyhvae.com/20210116-0946.png)
可以把size从到小排序看看哪个资源的文件较大
另外上图中的横线处说明该文件在网络传输的时候会做压缩125kb拿到资源之后再解压还原526kb
### performance性能表现
![](http://img.smyhvae.com/20210116-0959.png)
preformance的两个作用
- Record button记录页面加载用户交互等全过程直到我们手动点击停止按钮
- Reload button记录页面从刷新到资源加载完成的过程会自动停止记录
参数解读
- Timing关键的时间节点
- Main主线程做了哪些任务以及调用关系
Timing参数中尤其注意看`DCL`DOMContentLoaded即DOM加载完成的时间节点我们可以通过`Main`参数看看DOM在加载完成之前都做了些什么事情很有可能就是这些事情导致 `DCL`的时间过晚
我们可以翻到`Main`里的最后一行即最终调用的位置往往这个位置就是我们自己写的代码
### Diable cache
![](http://img.smyhvae.com/20210116-1014.png)
上图中的`Diable cache`是一个很重要的设置选项
勾选`Diable cache`
- 不走缓存相当于页面初次访问
- 如果你希望改的代码立即生效就一定要勾选上
不勾选`Diable cache`
- 走缓存相当于页面二次三次访问
- 很多时候我们需要关心用户在第二次第三次访问时候他的访问速度如何性能如何我们设置的缓存有没有生效此时就不要勾选上
### 模拟网络情况
![](http://img.smyhvae.com/20210116-1023.png)
模拟网络状况自定义参数
![](http://img.smyhvae.com/20210116-1026.png)
### Performance monitor
![](http://img.smyhvae.com/20210116-1032.png)
### 快捷键ESC
按住快捷键ESC会列出其他常用的功能菜单
![](http://img.smyhvae.com/20210116-1028.png)
## 使用 WebPageTest 评估网站性能
程序员经常说的有句话是我这儿能打开啊我这儿不报错呀大家应该都懂这个梗这就是为什么我们要借助第三方的测试工具而不仅仅只是自己电脑上访问正常就ok了
我们需要借助 WebPageTest 这样的第三方测试工具去模拟各种用户的真实场景
### WebPageTest 使用
网址<https://www.webpagetest.org>
![](http://img.smyhvae.com/20210115-2203.png)
WebPageTest 在世界各地提供了非常多的服务器在每个服务器上部署了不同的浏览器可以让我们有针对性的做测试如果你做的是一款国际化网站那更有必要使用一下了
我们以JD网站举例
![](http://img.smyhvae.com/20210115-2225.png)
按照上面的选项配置完成后点击右侧的Start Test即可开始测试然后等待
![](http://img.smyhvae.com/20210115-2226.png)
### 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 报告之后我们来看看报告里的几个重点指标
![](http://img.smyhvae.com/20210116_1314.png)
1摘要里的参数如上图
- First Byte第一个请求的响应时间可以反映后台的处理能力以及网络回路的情况
- Start Render从白屏到首次渲染的时间
- Speed Index速度指数
- **Total Blocking Time**页面被阻塞导致用户不能交互的累计时间
![](http://img.smyhvae.com/20210116_1315.png)
2详情里的参数**First View**
First View展示的是首次访问时总的加载时间这里面提供的瀑布图 chrome DevTools里提供的更为详细
点击进入 First View 的详情之后可以看到所有的资源请求都会在这里列出来如下
![](http://img.smyhvae.com/20210116_1316.png)
- page is Interactive页面在加载的过程中大部分时间段用户都是可以交互的这是非常有用的一个指标
- Brower Main thread浏览器主线程的占用情况可以看看空闲的时间多不多
- CPU UtilizationCPU的使用情况
- 多张图片的资源请求
![](http://img.smyhvae.com/20210116_1317.png)
上图中我们可以看到多张图片的开始请求时间都是相同的也就是说如果让资源做**并行加载**我们就可以加大地减少加载时间**最终所消耗的时间就由最大的图片来决定**这是一个很好的优化技巧至于具体是怎么实现的可以自行了解
另外我们看到有一部分的请求被高亮出来了
![](http://img.smyhvae.com/20210115-2250.png)
上面这张图的意思是302表示重定向也就是说这个资源已经不在原来请求的位置了需要重定向才能找到真实的位置这个地方其实可以做一个优化
> 不需要去访问之前的无效的资源可以直接去访问重定向后的那个资源
### 局域网部署 WebPageTest 工具
如果我们开发的页面还没有上线公网则无法访问这个时候我们也想通过WebPageTest看看网站的性能那要怎么办呢
我们可以在局域网部署 WebPageTest 工具具体方法可自行研究
## 使用LightHouse分析性能
我们之所以使用不同的性能测量工具是因为他们都有不同的特点WebPageTest 可以生成详细的性能测试报告 接下来要讲的 lighthouse 不仅可以帮我们生成测试报告还可以给出一些针对性的优化建议
### Lighthouse 介绍
![](http://img.smyhvae.com/20210115-1739.png)
lighthouse chrome 浏览器的一个性能测量工具我们先来看看它的性能指标至于它具体使用后续的内容再详细介绍
淘宝跑分举例
![](http://img.smyhvae.com/20210115-1758.png)
京东跑分举例
![](http://img.smyhvae.com/20210115-1759.png)
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报告
![](http://img.smyhvae.com/20210116_0107.png)
上图中给出了一个优化建议有些JS文件不是首屏加载必须的
![](http://img.smyhvae.com/20210116_0108.png)
我们随便拿一个JS文件来测试比如上图中Header标签里的JS文件做法如下
![](http://img.smyhvae.com/20210116-0901.png)
如上图所示 chrome 控制台输入快捷键Cmd + Shift + P然后输入文本`block`选择`Show Network request blocking`
![](http://img.smyhvae.com/20210116-0903.png)
按照上面的步骤添加规则点击add后效果如下
![](http://img.smyhvae.com/20210116-0904.png)
然后我们切换到控制台的 network面板并刷新页面
![](http://img.smyhvae.com/20210116-0905.png)
然后观察这个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来检测元素的可见状态
![](http://img.smyhvae.com/20210117_1635.png)
做曝光上报的埋点判断某个DOM或者某个楼层是否出现在视窗中出现了就收集数据上报给服务端
本质就是要计算某一元素和另一元素视窗的相对位置/相对可视状态然后进行一些操作一般是上报给服务端
参考
- [前端埋点之曝光实现](https://cnodejs.org/topic/5e0a0edb0696c446bf650dec)
- [点击埋点和曝光卖点的封装](https://github.com/Hugohui/vueTrackSdk)

View 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元素和属性但不包括展示性的和弃用的元素比如 fontu下划线等这些是被废弃了的
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元素和属性但包括展示性的和弃用的元素比如 fontu下划线等
3HTML 5
```html
<!DOCTYPE html>
```
**总结**
面试时不会让你写出 HTML 4.01的写法因为大家都记不住但是要记住 HTML 5 的写法别看它简单知道的人还真不多
面试时可以这样回答 HTML 4.01 中有两种写法一种是严格的一种是传统的并且答出二者的区别 HTML 5的写法是`<!DOCTYPE html>`
## 浏览器的渲染过程
### 渲染树
![](http://img.smyhvae.com/20210118-2005.png)
> 上方图片的来源[Google 官方 | 渲染树构建布局及绘制](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction?hl=zh-cn)
**渲染树**包含了网页中有哪些节点节点的从属关系以及节点的CSS样式大小颜色等
浏览器下载完html文档之后第一步是先将其解析成文本而html标签是由一对一对的尖括号表述的可以被浏览器解析为有含义的标记这些标记被翻译成节点对象存放到链型数据结构中这些节点被称之为**DOM对象**这个链型数据结构就是**渲染树**
### 渲染过程重要
浏览器的渲染过程非常复杂面试时找重点说就行不然太耗时间如何快速简洁地描述清楚是关键来看看下面这张图
![](http://img.smyhvae.com/20180310_1257.png)
渲染过程中涉及到以下几个概念
- DOM树DOM Tree浏览器将HTML标签解析成树形的数据结构DOM树包含了有哪些节点以及节点之间的从属关系嵌套关系
- CSSOMCSS 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
![](http://img.smyhvae.com/20210118-1950.jpg)
> 上方图片的来源<https://developers.google.com/web/fundamentals/performance/rendering>
关键渲染路径描述的是渲染从触发到绘制的全过程一共经历了五个阶段
1**触发视觉的变化**通过JSCSS代码来**触发**页面上的视觉变化比如通过 jQuery添加节点通过CSS添加动画都可以触发视觉上的变化
2Style浏览器对样式进行计算匹配选择器计算哪些CSS受到了影响
3layout同上一段
4painting同上一段
5conmposite同上一段
理论上上面的五个步骤都是必须要经历的布局和绘制是关键渲染路径中最重要开销最高的两个步骤
但是有些样式并不会影响布局也不会影响绘制所以浏览器对这方面的性能进行了优化并不一定要经历布局和绘制这两个过程这就需要我们先了解一下重排重绘这两个概念详见下一段
## 布局/回流/重排
### 定义
布局 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样式来修改的
- offsetLeftscrollTopclientWidth
- 修改浏览器窗口大小时即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)

View File

@@ -0,0 +1,169 @@
## 浏览器的渲染机制
我们需要先理解浏览器的渲染经历了哪些过程才能有针对性的进行相关优化
掌握浏览器的渲染优化可以说是前端工程师的一个分水岭如果想要具备架构师的思维需要达到什么样的能力不光是要解决当下的问题还需要掌握基本的原理将来在遇到新问题时也能解决预测问题
有一个经典的面试题是在浏览器的地址栏输入url回车后经历了哪些过程这个问题并不简单根据你回答的详细程度可以看出你对前后端知识的掌握程度你能否答出浏览器的渲染机制如果不能说明你对浏览器渲染的性能优化不够了解
关于浏览器的渲染机制可以看本教程的另外一篇文章
> 前端面试/面试必看/浏览器渲染机制.md
关键渲染路径举例
![image-20210323184157879](images/image-20210323184157879.png)
![image-20210323184551245](images/image-20210323184551245.png)
## 避免布局抖动layout thrashing
1尽量避免 重排
比如说如果想改变一个元素的位置很多人可能会使用相对布局的lefttop属性但是这个属性会引起重排我们可以使用 `transfrom:translate`让元素做位移这个属性既不会触发重排也不会触发 重绘只会触发 conmposite
再比如说vuereact这样的框架采用了虚拟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
![img](images/1*vSGOCrLV9MiLhpmPid1CHQ.png)
### V8引擎
## 补充
- 首屏尽快打开剩下的内容延迟加载减少初次加载的资源量首屏的内容是可以确定的

View File

@@ -0,0 +1,39 @@
## lazyload
用的最多的场景是
- 图片lazyload
- 组件lazyload
现在一般都单独做css的lazyload或者js的lazyload因为这种方式其实还是要加载图片和组件
### 图片lazyload
图片一般是页面最大的资源所以**非首屏**延迟加载很重要让首屏尽快显示
## 防抖动Debouncing和节流阀Throtting
参考链接
- [实例解析防抖动Debouncing和节流阀Throttling](http://www.css88.com/archives/7010)

View File

@@ -0,0 +1,593 @@
## 图片格式和应用场景
### JPEG 格式
JPEGJoint Photographic Experts Group是一种针对彩色照片而广泛使用的有损压缩图形格式属于位图
常用文件扩展名为`.jpg`也有 `.jpeg``.jpe`JPEG 在互联网上常被应用于存储和传输照片
- 适合颜色丰富的照片彩色图大焦点图通栏 banner 结构不规则的图形
- 不适合线条图形和文字图标图形因为它的压缩算法不太这些类型的图形并且不支持透明度
### PNG 格式
PNGPortable Network Graphics是一种无损压缩的位图图形格式支持索引灰度RGB 三种颜色方案以及 Alpha 通道等特性
PNG 最初是作为替代 GIF 来设计的能够显示 256 文件比 JPEG 或者 GIF 但是 PNG 非常好的保留了图像质量支持 Alpha 通道的半透明和透明特性最高支持 24 位彩色图像PNG-24 8 位灰度图像PNG-8
- 适合纯色**透明**线条绘图图标边缘清晰有大块相同颜色区域需要带**半透明**的图片
- 适合由于是无损存储所以不太适合体积太大的彩色图像
比如说如果你需要带透明背景的图片此时就可以用 png 格式的图
### GIF 格式
GIFGraphics 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图大图可以用 jpgwebp格式
- 图标带透明背景的图可以用 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逐步加载图像lazyloadLQIPLQIP
**方法1**使用统一占位符俗称图片的`懒加载lazyload`
**方法2**使用 **LQIP** 的图片加载方式也就是说在大图没有完全加载出来的情况下先这张图对应的的低质量图片进行占位
LQIPLow 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** 的图片加载方式
SQIPSVG 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 链接上增加不同特殊参数服务器自动化生成通过这些参数可以设置图片的不同格式大小质量
**常见处理方式**
- 图片裁剪按长边短边填充拉伸等缩放
- 图片格式转换支持 JPGGIFPNGWebP 支持不同的图片压缩率
- 图片处理添加图片水印高斯模糊重心处理裁剪边框等
- 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 transformsCSS3 transitionsOpacity 这样的属性会消耗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 字体库因为某些不可抗拒原因应该使用国内托管服务
### 6CSS 动画优化
- 尽量避免同时出现过多动画
- 延迟动画初始化让其他的重要的CSS样式优先渲染
- 结合 SVG
## JavaScript 总体优化
### 提升 JavaScript 文件加载性能
加载元素的顺序 CSS 文件放在 <head> JavaScript 文件放在 <body>
### JavaScript 变量和函数优化
- 尽量使用 id 选择器
- 尽量避免使用 eval
- JavaScript 函数尽可能保持简洁
- 使用事件节流函数
- 使用事件委托
### JavaScript 动画优化
- 避免添加大量 JavaScript 动画
- 尽量使用 CSS3 动画
- 尽量使用 Canvas 动画
- 合理使用 requestAnimationFrame 动画代替 setTimeoutsetInterval
- requestAnimationFrame可以在正确的时间进行渲染setTimeoutcallback和setIntervalcallback无法保证 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 里直接操作
现在流行的框架 AngularReactVue 都在使用虚拟 DOM 技术通过 diff 算法简化和减少 DOM 操作
## 静态文件压缩工具介绍
HTML 压缩工具
- html-minifierhttps://www.npmjs.com/package/html-minifier
CSS 压缩工具
- clean-csshttps://www.npmjs.com/package/clean-css
JavaScript 压缩工具
- uglify-jshttps://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 方式优化

View File

@@ -0,0 +1,369 @@
## 浏览器渲染过程
![](https://img.smyhvae.com/20210114_2115.png)
1. 浏览器解析 HTML生成 DOM TreeParse HTML
2. 浏览器解析 CSS生成 CSSOMCSS Object ModelTree
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 AppReactVuePWA
- Hybrid AppPhoneGap AppCan
- 跨平台开发RN Flutter 小程序等
- 原生 AppiOS Android
建议
- 依赖业务形式依赖团队规模依赖技术水平
## 静态化技术方案
静态化是使动态化的网站生成静态 HTML 页面以供用户更好访问的技术一般分为纯动态化和伪动态化
技术优势
- 提高了页面访问速度降低了服务器的负担因为访问页面时不需要每次去访问数据库
- 提高网站内容被搜索引擎搜索到的几率因为搜索引擎更喜欢静态页面
- 网站更稳定如果后端程序数据库出现问题会直接影响网站的正常访问而静态化页面有缓存更不容易出现问题
技术不足
- 服务器存储占用问题因为页面量级在增加要占用大量硬盘空间
- 静态页面中的链接更新问题会有死链或者错误链接问题
技术实现
- 跑定时任务将已有的动态内容进行重定生成静态的 HTML 页面
- 利用模板技术将模板引擎中模板字符替换为从数据库字段中取出来的值 同时生成 HTML 文件
协作方式
- 前端统一写好带有交互的完整静态页面
- 后端拆分出静态页面文件并嵌套在后端模板文件中
选型建议后端研发人员充分又需要考虑用户体验服务器负载的业务
## 前后端分离技术与实现
前后端分离是指研发人员分离业务代码分离后端实现业务接口前端渲染页面
技术实现
- 后端只负责功能接口实现提供按照约定的数据格式并封装好的 API 接口
- 前端负责业务具体实现获取到 API 接口数据后进行页面模板拼接和渲染独立上线
协作方式
- 前端负责实现页面前端交互根据后端 API 接口拼装前端模板
- 后端专注于业务功能实现和 API 接口封装
技术优势
- 团队更加专注
- 提升了开发效率
- 增加代码可维护性
技术架构
- 后端架构JavaC++PHP + Nginx使用微服务比如 Dubbo 等实现业务的解耦所有的服务使用某种协议提供不同的服务比如 JSF
- 前端架构使用 AngularReactVue 前端框架并部署页面至 CDN
- 前端架构 2使用 AngularReactVue 前端框架并部署在 Node Server
技术不足
- 因为前端需要负责一大部分业务逻辑实现和服务端同步静态化需要前端人力非常多
- 页面数据异步渲染不利于 SEO搜索引擎更喜欢纯静态页面
选型建议
- 这是大型互联网公司正在采用的开发模式一句话如果考虑用户体验以及前端人力够用就可以积极采用
## 单页面应用技术方案
单页应用single-page application缩写 SPA通过动态重写当前页面来与用户交互而非传统的从服务器重新加载整个新页面这种方法在使用过程中不需要重新加载页面避免了页面之间切换打断用户体验使应用程序更像一个桌面应用程序
技术优点
- 不错的加载速度用户往往感觉页面加载非常快因为一进入页面就能看到页面元素
- 良好的交互体验进行局部渲染避免不必要的页面间跳转和重复渲染
- 前后端职责分离前端进行页面交互逻辑后端负责业务逻辑
- 减轻服务器负载服务器只处理数据接口输出不用考虑页面模板渲染和 HTML 展示
技术缺点
- 开发成本相对较高
- 首次页面加载时间过多
- SEO 难度比较大
技术实现
- 使用 ReactVue 框架可以很好的
## 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简称 PWAPWA 应用是使用特定技术和标准模式来开发的 Web 应用这将同时赋予它们 Web 应用和原生应用的特性
技术优势
- 用户可以用手机屏幕启动应用即使在离线状态或者弱网下通过事先缓存的资源也可正常加载运行当前应用可以完全消除对网络的依赖从而给用户非常可靠的体验
- 因为预先缓存了资源部分资源无须经过网络即秒开页面
- 和移动设备上的原生应用一样具有沉浸式的用户体验
- 可以给用户发送离线推送消息
技术实现
- 全站改造成 HTTPS没有 HTTPS 就没有 Service Worker
- 应用 Service Worker 技术提升性能离线提供静态资源文件提升首屏用户体验
- 使用 App Manifest
- 最后可以考虑离线消息推送等功能
浏览器兼容性
- ServiceWorkerGlobalScope API88%
- 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使用 preloadprefetch 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也包括弱网超时网络异常网络切换等一段情况的监控情况排查出来问题后需要联合后端运维网络岗位人员一并解决
## 接口缓存策略优化
1Ajax/fetch 缓存前端请求时候带上 cache依赖浏览器本身缓存机制
2本地缓存异步接口数据优先使用本地 localStorage 中的缓存数据
3多次请求接口数据本地无 localStorage 缓存数据重新再次发出 ajax 请求