一, 课程简介:
1, 课程大纲
涉及到的分类
网络层面
构建层面
浏览器渲染层面
服务端层面
涉及到的功能点
资源的合并与压缩
图片编解码原理和类型选择
浏览器渲染机制
懒加载预加载
浏览器存储
缓存机制
PWA
vue-SSR
前端性能优化原理
作用及原理
如何与真实业务场景结合
理论结合实践
量化分析
课程安排
基础优化 1-3 章
进阶优化 4-7 章
综合服务优化 9 章
回顾总结 10 章
二, 资源合并与压缩
1,http 请求的过程及潜在的性能优化点
课程目标
理解
减少 http 请求数量
和
减少请求资源大小
两个优化要点
掌握压缩与合并的原理
掌握通过在线网站和 fis3 两种实现压缩与合并的方法 #### 浏览器的一个请求从发送到返回都经历了什么 动态的加载静态的资源
1,dns 是否可以通过缓存减少 dns 查询时间
2, 网络请求的过程走最近的网络环境
3, 相同的静态资源是否可以缓存
4, 能否减少 http 请求大小
5, 能否减少 http 请求数量
6, 服务端渲染
2,html 压缩
资源的合并与压缩设计到的性能点:
1, 减少 http 请求的数量
2, 减少请求的大小
google 首页案例分析
1,HTML 压缩
2,CSS 压缩
3,JS 的压缩与混乱
4, 文件合并
5, 开启 gzip
如何进行 HTML 的压缩
1, 使用在线网站进行压缩
2,node.JS 提供了 HTML-minifier 工具
3, 后端模板引擎渲染压缩
3,CSS 及 JS 压缩
CSS 的压缩
1, 无效代码删除
2,CSS 语义合并
CSS 压缩的方式
1, 使用在线网站进行压缩
2, 使用 HTML-minifier 对 HTML 中的 CSS 进行压缩
3, 使用 clean-CSS 对 CSS 进行压缩
JS 的压缩语混乱
1, 无效字符的删除
2, 剔除注释
3, 代码语意的缩减和优化
4, 代码保护
JS 压缩的方式
1, 使用在线网站进行压缩
2, 使用 HTML-minifier 对 HTML 中的 JS 进行压缩
3, 使用 uglifyjs2 对 JS 进行压缩
4, 文件合并优点
1, 文件与文件有插入之间的上行请求, 又增加了 N-1 个网络延迟
2, 受丢包问题影响更严重
3, 经过代理服务器时可能会被断开
文件合并缺点
1, 首屏渲染问题
2, 缓存失效问题
文件合并对应缺点的处理
1, 公共库合并
2, 不同页面的合并
3, 见机行事, 随机应变
文件合并对应方法
1, 使用在线网站进行合并
2, 使用 Node.JS 进行文件合并
三, 图片相关优化
课程目标
理解图片相关的优化的核心概念
结合 Facebook 和淘宝移动首页案例分析
掌握通过在线网站和 fis3 两种实现图片相关的一些优化
1, 一张 JPG 的解析过程
jpg 有损压缩: 虽然损失一些信息, 但是肉眼可见影响并不大
2,png8/png24/png32 之间的区别
png32 是在 png24 上支持了透明, 针对不同的业务场景选择不同的图片格式很重要
3, 不同的格式图片常用的业务场景
不同格式图片的特点
1,jpg 有损压缩, 压缩率高, 不支持透明
2,PNG 支持透明, 浏览器兼容性好
3,webp 压缩程度更好 , 在 iOS webview 中有兼容性问题
4,svg 矢量图, 代码内嵌, 相对较小, 图片样式相对简单的场景(尽量使用, 绘制能力有限, 图片简单用的比较多)
不同格式图片的使用场景
1,jpg: 大部分不需要透明图片的业务场景
2,PNG: 大部分需要透明图片的业务场景
3,webp:Android 全部(解码速度和压缩率高于 jpg 和 PNG, 但是 iOS Safari 还没支持)
4,svg: 图片样式相对简单的业务场景
4, 图片压缩的几种情况
1, 针对真实图片情况, 舍弃一些相对无关紧要的色彩信息
2,CSS 雪碧图: 把你的网站用到的一些图片整合到一张单独的图片中
- // 优点: 减少 HTTP 请求的数量(通过 backgroundPosition 定位所需图片)
- // 缺点: 整合图片比较大时, 加载比较慢(如果这张图片没有加载成功, 整个页面会失去图片信息)Facebook 官网任然在用, 主要 pc 用的比较多, 相对性能比较强
3,Image-inline: 将图片的内容嵌到 HTML 中 //base64 信息, 减少网站的 HTTP 请求, 如果图片比较小比较多, 时间损耗主要在请求的骨干网络
4, 使用矢量图: 使用 SVG 进行矢量图的绘制, 使用 icon-font 解决 icon 问题
5, 在 Android 下使用 webp:webp 的优势主要体现在它具有更优的图像数据压缩算法, 能带来更小的图片体积, 而且拥有肉眼识别无差异的图像质量; 同时具备了无损和有损的压缩模式, Alpha 透明以及动画的特性, 在 JPEG 和 PNG 上的转化效果都非常优秀, 稳定和统一
四, CSS 和 JS 的装载与执行
课程目标
理解浏览器端 HTML,CSS,JS 的装载过程
结合 Chrome 的能力学习掌握 CSS,JS 加载过程中的优化点
通过案例分析和实战演练深入理解学习的优化点
1,HTML 页面加载渲染的过程
一个网站在浏览器端是如何进行渲染的
2,HTML 渲染过程中的一些特点
顺序执行, 并发加载
是否阻塞
依赖关系
引入方式
阻塞的几种方式:
CSS 的加载是否会阻塞 JS 的加载
CSS 的加载是否会阻塞 JS 的执行
CSS 的加载是否会影响页面的渲染
JS 的执行是否会阻塞 JS 的执行和 JS 的加载
依赖:
如果我们把 CSS 代码放在 head 中去引入的话, 那么我们整个页面的渲染实际上就会等待 head 中 CSS 加载并生成 CSS 树, 最终和 DOM 整合生成 RanderTree 之后才会进行渲染
JS async 异步加载
引入:
script src 引入有相关阻塞页面行为
JS 资源是否需要动态加载
3, 顺序执行, 并发加载
词法分析
并发加载
并发上限
4,CSS 阻塞和 JS 阻塞
CSS 阻塞
CSS head 中阻塞页面的渲染
CSS 阻塞 JS 的执行
CSS 不阻塞外部脚步的加载
CSS head 中通过 link 方式引入, 避免页面闪动, 因为这样只有等 CSS 加载完才会渲染
JS 的执行很可能要操作 DOM
JS 阻塞
直接引入的 JS 阻塞页面的渲染
JS 不阻塞资源的加载
JS 顺序执行, 阻塞后续 JS 的执行
直接通过 script src 在 head 中引入, HTML parse 认为 JS 会动态修改文档结构, 没有进行后面文档的分析
五, 懒加载与预加载
理解懒加载和预加载的原理
懒加载和预加载的案例分析
懒加载与预加载的案例实战
1, 懒加载原理
图片进入可视区域之后请求图片资源
对于电商等图片很多, 页面很长的业务场景适用
减少无效资源的加载
并发加载的资源过多会会阻塞 JS 的加载, 影响网站的正常使用
img src 被设置之后, webkit 解析到之后才去请求这个资源. 所以我们希望图片到达可视区域之后, img src 才会被设置进来, 没有到达可视区域前并不现实真正的 src, 而是类似一个 1px 的占位符.
2, 预加载原理
图片等静态资源在使用之前的提前请求
资源使用到时能从缓存中加载, 提升用户体验
页面展示的依赖关系维护
3, 懒加载原生 JS 和 zepto.lazyload
1, 原理: 先将 img 标签中的 src 链接设为同一张图片(空白图片), 将其真正的图片地址存储再 img 标签的自定义属性中(比如 data-src). 当 JS 监听到该图片元素进入可视窗口时, 即将自定义属性中的地址存储到 src 属性中, 达到懒加载的效果.
注意问题: 1, 关注首屏处理, 因为还没滑动 2, 占位, 图片大小首先需要预设高度, 如果没有设置的话, 会全部显示出来
4, 预加载原生 JS 和 preloadJS 实现
预加载实现的几种方式
第一种方式: 直接请求下来
- <img src="www.pic27.com/sadfafd/dafdsa.jpg" style="display: none" />
- <img src="www.pic27.com/sadfafd/dsaf.jpg" style="display: none" />
- <img src="www.pic27.com/sadfafd/dasfd.jpg" style="display: none" />
- <img src="www.pic27.com/sadfafd/fdsa.jpg" style="display: none" />
第二种方式: image 对象
- var image = new Image();
- image.src = "www.pic26.com/dafdafd/safdas.jpg";
第三种方式: xmlhttprequest
缺点: 存在跨域问题
优点: 好控制
本质: 平衡浏览器加载能力, 让它尽可能饱和起来
六, 重绘与回流
理解浏览器重绘与回流的机制
对于一些经典的案例进行分析
重绘与回流的案例分析
1,CSS 性能让 JavaScript 变慢
要把 CSS 相关的外部文件引入放进 head 中, 加载 CSS 时, 整个页面的渲染是阻塞的, 同样的执行 JavaScript 代码的时候也是阻塞的, 例如 JavaScript 死循环.
一个线程 => JavaScript 解析
一个线程 => UI 渲染
这两个线程是互斥的, 当 UI 渲染的时候, JavaScript 的代码被终止. 当 JavaScript 代码执行, UI 线程被冻结. 所以 CSS 的性能让 JavaScript 变慢.
频繁触发重绘与回流, 会导致 UI 频繁渲染, 最终导致 JS 变慢
2, 什么是重绘和回流
回流
当 render tree 中的一部分 (或全部) 因为元素的规模尺寸, 布局, 隐藏等改变而需要重新构建. 这就成为回流(reflow)
当页面布局和几何属性改变时, 就需要回流
重绘
当 render tree 中的一些元素需要更新属性, 而这些属性只是影响元素的外观, 风格, 而不影响布局, 比如 background-color. 就称重绘
关系
回流必将引起重绘, 但是重绘不一定会引起回流
3, 避免重绘, 回流的两种方法
触发页面重布局的一些 CSS 属性
盒子模型相关属性会触发重布局
width,height,padding,margin,display,border-width,border,min-height
定位属性及浮动也会触发重布局
top,bottom,left,right,position,float,clear
改变节点内部文字结构也会触发重布局
text-align,overflow-y,font-weight,overflow,font-family,line-height,vertical-align,white-space,font-size
优化点: 使用不触发回流的方案替代触发回流的方案
只触发重绘不触发回流
- color,
- border-style,border-radius,
- visibility,
- text-decoration,
- background,background-image,background-position,background-repeat,background-size,
- outline,outline-color,outline-style,outline-width
- box-shadow
新建 DOM 的过程
1, 获取 DOM 后分割为多个图层
2, 对每个图层的节点计算样式结果(Recalculate style 样式重计算)
3, 为每个节点生成图形和位置(Layout 回流和重布局)
4, 将每个节点绘制填充到图层位图中(Paint Setup 和 Paint 重绘)
5, 图层作为纹理上传至 gpu
6, 符合多个图层到页面上生成最终屏幕图像(Composite Layers 图层重组)
Chrome 创建图层的条件
将频繁重绘回流的 DOM 元素单独作为一个独立图层, 那么这个 DOM 元素的重绘和回流的影响只会在这个图层中
1,3D 或透视变换 CSS 属性(perspective transform)
2, 使用加速视频解码的 < video > 节点
3, 拥有 3D(webGl)上下文或加速的 2D 上下文的 < canvas > 节点
4, 混合插件(如 Flash)
5, 对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
6, 拥有加速 CSS 过滤器的元素
7, 元素有一个包含复合层的后代节点(一个元素拥有一个子元素, 该子元素在自己的层里)
8, 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说, 就是该元素在复合层上层渲染)
gif 图
总结
1, 避免使用触发回流, 重绘的 CSS 属性 2, 将重绘, 回流的影响范围限制在单独的图层 (layers) 之内 3, 图层合成过程中消耗很大页面性能, 这时候需要平衡考虑重绘回流的性能消耗
4, 实战优化点总结
1, 用 translate 替代 top 属性
2, 用 opacity 代替 visibility
- //opacity 不会触发重绘也不会触发回流, 只是改变图层 alpha 值, 但是必须要将这个图片独立出一个图层
- //visibility 会触发重绘
3, 不要一条一条的修改 DOM 的样式, 预先定义好 class, 然后修改 DOM 的 className
4, 把 DOM 离线后修改, 比如: 先把 DOM 给 `display:none`(有一次 reflow), 然后你修改 100 次, 然后再把它显示出来
5, 不要把 DOM 节点的属性值放在一个循环里当成循环的变量
6, 不要使用 table 布局, 可能很小的一个小改动会造成整个 table 的重新布局
//div 只会影响后续样式的布局
7, 动画实现的速度的选择
// 根据 performance 量化性能优化
8, 对于动画新建图层
9, 启用 gpu 硬件加速(并行运算),gpu 加速意味着数据需要从 CPU 走总线到 gpu 传输, 需要考虑传输损耗
- //transform:translateZ(0)
- //transform:translate#d(0)
七, 浏览器存储
链接 localstorage,cookie,sessionstorage,indexedDB 的概念和使用
学习理解 pwa 和 service worker 的应用
案例分析和实战
1,cookies
多种浏览器存储方式并存, 如何选择?
1, 因为 http 请求无状态, 所以需要 cookie 去维持客户端状态
2,cookie 的生成方式: 1.http response header set-cookie
2.JS 中可以通过 document.cookie 可以读写 cookie
3,cookie 的使用用处: 1. 用于浏览器端和服务器端的交互(用户状态)
2. 客户端自身数据的存储
4,expire: 过期时间
5,cookie 的限制: 1. 作为浏览器存储, 大小 4kb 左右
2. 需要设置过期时间 expire
6, 重要属性: httponly 不支持 JS 读写(防止收到模拟请求攻击)
7, 不太作为存储方案而是用于维护客户关系
8, 优化点: cookie 中在相关域名下面 - cdn 的流量损耗
解决方案: cdn 的域名和主站域名要分开
- 2,localStorage
- localstorage
1,HTML5 设计出来专门用于浏览器存储的
2, 大小为 5M 左右
3, 仅在客户端使用, 不和服务端进行通信
4, 接口封装较好
5, 浏览器本地缓存方案
sessionstorage
会话级别的浏览器存储
大小为 5M 左右
仅在客户端使用, 不和服务器端进行通信
接口封装较好
对于表单信息的维护
3,indexedDB
IndexedDB 是一种低级 API, 用于客户端存储大量结构化数据. 该 API 使用索引来实现对该数据的高性能搜索. 虽然 Web Storage 对于存储叫少量的数据很管用, 但对于存储更大量的结构化数据来说, 这种方法不太有用. IndexedDB 提供了一个解决方案.
为应用创建离线版本.
cdn 域名不要带 cookie
localstorage 存库, 图片
4,Service Worker 产生的意义
5,PWA 与 Service Worker
PWA(Progressive Web Apps)是一种 Web App 新模型, 并不是具体指某一种前言的技术或者某一个单一的知识点, 我们从英文缩写来看就能看出来, 这是一个渐进式的 Web App, 是通过一系列新的 Web 特性, 配合优秀的 UI 交互设计, 逐步增强 Web App 的用户体验
6,PWA 与 Service worker
Chrome 插件 lighthouse
检测是不是一个渐进式 Web App
1, 当前手机在弱网环境下能不能加载出来
2, 离线环境下能不能加载出来
...
1, 可靠: 没有网络的环境中也能提供基本的页面访问, 而不会出现 "未连接到互联网" 的页面
2, 快速: 针对网页渲染及网络数据访问有较好的优化
3, 融入(Engaging): 应用可以被增加到手机桌面, 并且和普通应用一样有全屏, 推送等特性
####service worker
service worker 是一个脚本, 浏览器独立于当前页面, 将其在后台运行, 为实现一些不依赖页面的或者用户交互的特性打开了一扇大门. 在未来这些特性将包括消息推送, 背景后台同步, geofencing(地理围栏定位), 但他将推出的第一个首要的特性, 就是拦截和处理网络请求的能力, 包括以编程方式来管理被缓存的响应.
案例分析
- Chrome://serviceworker-internals/
- Chrome://inspect/#service-worker/
service worker 网络拦截能力, 存储 Cache Storage, 实现离线应用
indexedDB
callback && callback()写法
相当于
- if(callback){
- callback();
- }
7,cookie,session,localStorage,sessionStorage 基本操作
8,indexedDB 基本操作
object store: 对象存储
本身就是结构化存储
- function openDB(name, callback) {
- // 建立打开 indexdb indexedDB.open
- var request = Windows.indexedDB.open(name)
- request.onerror = function(e) {
- console.log('on indexedDB error')
- }
- request.onsuccess = function(e) {
- myDB.db = e.target.result
- callback && callback()
- }
- //from no database to first version,first version to second version...
- request.onupgradeneeded = function() {
- console.log('created')
- var store = request.result.createObjectStore('books', {
- keyPath: 'isbn'
- })
- console.log(store)
- var titleIndex = store.createIndex('by_title', 'title', {
- unique: true
- })
- var authorIndex = store.createIndex('by_author', 'author')
- store.put({
- title: 'quarry memories',
- author: 'fred',
- isbn: 123456
- })
- store.put({
- title: 'dafd memories',
- author: 'frdfaded',
- isbn: 12345
- })
- store.put({
- title: 'dafd medafdadmories',
- author: 'frdfdsafdafded',
- isbn: 12345434
- })
- }
- }
- var myDB = {
- name: 'tesDB',
- version: '2.0.1',
- db: null
- }
- function addData(db, storeName) {
- }
- openDB(myDB.name, function() {
- // myDB.db = e.target.result
- // Windows.indexedDB.deleteDatabase(myDB.name)
- });
- // 删除 indexedDB
9,indexDB 事务
transcation 与 object store 建立关联关系来操作 object store
建立之初可以配置
- var transcation = db.transcation('books', 'readwrite')
- var store = transcation.objectStore('books')
- var data =store.get(34314)
- store.delete(2334)
- store.add({
- title: 'dafd medafdadmories',
- author: 'frdfdsafdafded',
- isbn: 12345434
- })
10,Service Worker 离线应用
serviceworker 需要 https 协议
11, 如何实现 ServiceWorker 与主页面之间的通信
详细学习 https://lavas.baidu.com/guide/v1/foundation/lavas-start
八, 缓存
期望大规模数据能自动化缓存, 而不是手动进行缓存, 需要浏览器端和服务器端协商一种缓存机制
理解 Cache-Control 所控制的缓存策略
学习理解 last-modified 和 etage 以及整个服务端浏览器端的缓存流程
案例分析和实战, 基于 node 实践以上缓存方式
1,httpheader
可缓存性
1, public: 表明响应可以被任何对象 (包括: 发送请求的客户端, 代理服务器, 等等) 缓存.
2, private: 表明响应只能被单个用户缓存, 不能作为共享缓存(即代理服务器不能缓存它).
3, no-cache: 强制所有缓存了该响应的缓存用户, 在使用已存储的缓存数据前, 发送带验证器的请求到原始服务器
4, only-if-cached: 表明如果缓存存在, 只使用缓存, 无论原始服务器数据是否有更新
到期
1, max-age=<seconds>: 设置缓存存储的最大周期, 超过这个时间缓存被认为过期(单位秒). 与 Expires 相反, 时间是相对于请求的时间.
2, s-maxage=<seconds>: 覆盖 max-age 或者 Expires 头, 但是仅适用于共享缓存(比如各个代理), 并且私有缓存中它被忽略. cdn 缓存
3, max-stale[=<seconds>]
表明客户端愿意接收一个已经过期的资源. 可选的设置一个时间(单位秒), 表示响应不能超过的过时时间.
4, min-fresh=<seconds>
表示客户端希望在指定的时间内获取最新的响应.
重新验证和重新加载
1,must-revalidate: 缓存必须在使用之前验证旧资源的状态, 并且不可使用过期资源.
2,proxy-revalidate: 与 must-revalidate 作用相同, 但它仅适用于共享缓存(例如代理), 并被私有缓存忽略.
3,immutable : 表示响应正文不会随时间而改变. 资源 (如果未过期) 在服务器上不发生改变, 因此客户端不应发送重新验证请求头 (例如 If-None-Match 或 If-Modified-Since) 来检查更新, 即使用户显式地刷新页面. 在 Firefox 中, immutable 只能被用在 https:// transactions.
1,no-store: 缓存不应存储有关客户端请求或服务器响应的任何内容.
2,no-transform: 不得对资源进行转换或转变. Content-Encoding, Content-Range, Content-Type 等 HTTP 头不能由代理修改. 例如, 非透明代理可以对图像格式进行转换, 以便节省缓存空间或者减少缓慢链路上的流量. no-transform 指令不允许这样做.
- 2,Expires
- Expires
1, 缓存过期时间, 用来指定资源到期的时间, 是服务器端的时间点
2, 告诉浏览器在过期时间前浏览器可以直接从浏览器缓存中存取数据, 而无需再次请求
1,expires 是 http1.0 的时候的
2,http1.1 时候, 我们希望 cache 的管理统一进行, max-age 优先级高于 expires, 当有 max-age 在的时候 expires 可能就会被忽略.
3, 如果没有设置 cache-control 时候会使用 expires
3,Last-modified 和 If-Modified-since
1, 基于客户端和服务器端协商的缓存机制
- 2, last-modified --> response header
- if-modified-since --> request header
3, 需要与 cache-control 共同使用
304:
200:
last-modified 有什么缺点?
1, 某些服务端不能获取精确的修改时间
2, 文件修改时间改了, 但文件的内容却没有变
4,Etag 和 If-none-match
1, 文件内容的 hash 值
- 2,etag -->reponse header
- if-none-match -->request header
3, 需要与 cache-control 共同使用
好处:
比 if-modified-since 更加准确
优先级比 etage 更高
4, 流程图
九, 服务端性能优化
服务端用的 node.JS 因为和前端用的同一种语言, 可以利用服务端运算能力来进行相关的运算而减少前端的运算
课程目标
理解 vue 渲染遇到的问题
学习理解 vue-ssr 和原理和引用
按理分析和实战
vue 渲染面临的问题
先加载 vue.js
=> 执行 vue.JS 代码
=> 生成 HTML
以前没有前端框架时,
用 jsp/PHP` 在服务端进行数据的填充 `, 发送给客户端就是已经 ` 填充好数据 ` 的 HTML
使用 jQuery 异步加载数据
使用 React 和 Vue 前端框架
怎么在 vue 这个层面对性能进行提升
1, 构建层的模板编译(runtime,compile 拆开), 构建层做模板编译工作. webpack 构建时候, 统一, 直接编译成 runtime 可以执行的代码
2, 数据无关的 prerender 的方式
3, 服务端渲染
来源: https://juejin.im/post/5c011e0c5188252ea66afdfa