├── cache
├── mime.js
├── assets
│ └── view.png
├── config.js
└── app.js
├── 资源合并与压缩
└── html 压缩.html
├── cookie
└── index.html
├── 预加载
├── index.html
└── my_reload.js
├── localstorage
└── index.html
├── SessionStorage
└── index.html
├── 重绘和回流
├── 03.html
├── 02.html
└── 01.html
├── 懒加载
├── lazyload.js
└── index.html
└── README.md
/cache/mime.js:
--------------------------------------------------------------------------------
1 | exports.types = {
2 | 'png': 'image/png',
3 | 'json': 'application/json'
4 | };
--------------------------------------------------------------------------------
/cache/assets/view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heidoua/Web_Performance_Optimization/HEAD/cache/assets/view.png
--------------------------------------------------------------------------------
/cache/config.js:
--------------------------------------------------------------------------------
1 | exports.Expires = {
2 | maxAge: 60 * 60 * 24 * 365,
3 | fileMatch: /^(gif|png|jpg|js|css)$/ig
4 | };
--------------------------------------------------------------------------------
/资源合并与压缩/html 压缩.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
12 |
13 |
--------------------------------------------------------------------------------
/cookie/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/预加载/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
19 |
20 |
--------------------------------------------------------------------------------
/localstorage/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/SessionStorage/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/重绘和回流/03.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
17 |
18 |
19 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/重绘和回流/02.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
18 |
19 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/预加载/my_reload.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: FangFeiyue
3 | * @Date: 2017-10-16 15:29:15
4 | * @Last Modified by: FangFeiyue
5 | * @Last Modified time: 2017-10-16 16:14:28
6 | */
7 |
8 | // LoadQueue是一个加载管理器,可以预先加载一个文件或者一个文件队列
9 | var queue = new createjs.LoadQueue(false);
10 |
11 | // 为事件添加你想要的监听事件
12 | queue.on("complete", handleComplete, this);
13 |
14 | // 或添加多个文件使用列表或一个清单定义使用 loadManifest
15 | queue.loadManifest([
16 | {id: "myImage", src:"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=996503075,3768564257&fm=200&gp=0.jpg"},
17 | {id: "myImage2", src:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4287850242,3208290927&fm=200&gp=0.jpg"}
18 | ]);
19 |
20 | function handleComplete() {
21 | var image = queue.getResult("myImage");
22 | document.body.appendChild(image);
23 | }
--------------------------------------------------------------------------------
/重绘和回流/01.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
19 |
20 |
21 |
22 |
28 |
29 |
--------------------------------------------------------------------------------
/懒加载/lazyload.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: FangFeiyue
3 | * @Date: 2017-10-16 13:35:19
4 | * @Last Modified by: FangFeiyue
5 | * @Last Modified time: 2017-10-16 13:45:52
6 | */
7 | var lazyLoadJS = {
8 | viewHeight: document.documentElement.clientHeight,
9 | init: function(){
10 | this.onLoad();
11 | },
12 | onLoad: function(){
13 | var _this = this;
14 | this.layzyLoad();
15 | document.addEventListener('scroll', function(){_this.layzyLoad()});
16 | },
17 | layzyLoad: function(){
18 | var _this = this,
19 | eles = document.querySelectorAll('img[data-original][lazyload]');
20 |
21 | Array.prototype.forEach.call(eles, function(item, index){
22 | var rect;
23 | if (item.dataset.original === ''){
24 | return;
25 | }
26 | rect = item.getBoundingClientRect();
27 |
28 | if ((rect.bottom >= 0) && (rect.top < _this.viewHeight)){
29 | !function(){
30 | var img = new Image();
31 | img.src = item.dataset.original;
32 | img.onload = function(){
33 | item.src = img.src;
34 | };
35 | item.removeAttribute('data-original');
36 | item.removeAttribute('lazyload');
37 | }();
38 | }
39 | });
40 | },
41 | };
42 |
43 | lazyLoadJS.init();
44 |
45 |
--------------------------------------------------------------------------------
/cache/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: FangFeiyue
3 | * @Date: 2017-10-20 09:10:09
4 | * @Last Modified by: FangFeiyue
5 | * @Last Modified time: 2017-10-20 09:53:50
6 | */
7 | /*
8 | 读写文件
9 |
10 | 1. 文件存在
11 | 1.读写成功
12 | 2.读写失败
13 | 2. 文件不存在
14 | */
15 | var PORT = 8000,
16 | fs = require('fs'),
17 | url = require('url'),
18 | http = require('http'),
19 | path = require('path'),
20 | mime = require('./mime').types;
21 | config = require('./config');
22 |
23 | var server = http.createServer(function(request, response){
24 | var contentType,
25 | pathName = url.parse(request.url).pathname,
26 | realPath = 'assets' + pathName,
27 | ext = path.extname(realPath);
28 |
29 | ext = ext ? ext.slice(1) : 'unknown';
30 | contentType = mime[ext] || "text/plain";
31 |
32 | if (ext.match(config.Expires.fileMatch)){
33 | var expires = new Date();
34 | expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
35 | response.setHeader('Expires', expires.toUTCString());
36 | response.setHeader('Cache-Control', 'max-age=' + config.Expires.maxAge);
37 | }
38 |
39 | fs.stat(realPath, function(err, stat){
40 | var last
41 | });
42 |
43 | fs.exists(realPath, function(exists){
44 | if (!exists){
45 | response.writeHead(404, {
46 | 'Content-type': contentType
47 | });
48 |
49 | response.write('This request URL ' + pathName + ' was not found');
50 | response.end();
51 | }else{
52 | fs.readFile(realPath, 'binary', function(err, file){
53 | if (err){
54 | response.writeHead(500, {
55 | 'Content-type': contentType
56 | });
57 | response.write('read file is error');
58 | response.end();
59 | }else{
60 | response.writeHead(200, {
61 | 'Content-type': contentType
62 | });
63 |
64 | response.write(file, 'binary');
65 | response.end();
66 | }
67 | });
68 | }
69 | });
70 | });
71 |
72 | server.listen(PORT);
73 | console.log('Server runing at port' + PORT);
--------------------------------------------------------------------------------
/懒加载/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
20 |
21 |
22 |
23 |
![]()
24 |
![]()
25 |
![]()
26 |
![]()
27 |
![]()
28 |
![]()
29 |
![]()
30 |
![]()
31 |
![]()
32 |
![]()
33 |
![]()
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Web前端性能优化
2 | ## 简介
3 | 几乎所有的开发者都会面临着开发的网站存在加载问题,想要加快网页的加载速度前端的页面更需要在性能优化上下功夫,只有这样才能实现更好的用户体验。
4 |
5 | 本文根据自己的学习笔记、工作经验总结而来,从构建、浏览器渲染、缓存、PWA、服务端优化等多方面,梳理前端性能优化的技术点、综合分析技术的原理,根据不同的业务场景选择合适的性能优化点进行应用,最终为你的网站带来显著的速度提升和整体性能提升。
6 | ## 注意
7 | 性能优化要见机行事,随机应变,坚持中庸的思想,不可过度优化。
8 | ## 设计到的前端性能优化点、功能点
9 | - 网络层面
10 | - 构建层面
11 | - 服务端层面
12 | - 浏览器渲染层面
13 | - 资源的合并与压缩
14 | - 图片编解码原理和类型选择
15 | - 浏览器的渲染机制
16 | - 懒加载预加载
17 | - 浏览器存储
18 | - 缓存机制
19 | - PWA
20 | - Vue-SSR
21 | ## 资源的合并与压缩
22 | - 目标
23 | - 理解减少http请求数量和减少请求资源大小两个优化要点
24 | - 掌握压缩和合并的原理
25 | - 掌握通过在线网站和fis3两种实现压缩与合并的方法
26 | 浏览器的一个请求从发送到返回都经历了什么?
27 |
28 | 
29 |
30 | - html压缩
31 | - css压缩
32 | - js压缩
33 | - 文件合并
34 | - 文件合并可能产生的问题
35 | - 首屏渲染的问题
36 | - 缓存失效的问题
37 | - 文件合并的建议
38 | - 公共库合并
39 | - 不同页面的合并
40 | ## 图片相关的优化
41 | - png8/png24/png32之间的区别
42 | - png8--256色 + 支持透明
43 | - png24--2^24色 + 不支持透明
44 | - png32--2^24 + 支持透明
45 | - 不同格式图片常用的业务场景
46 | - jpg有损压缩,压缩率高,不支持透明,适用于大部分不需要透明图片的业务场景
47 | - png支持透明,浏览器兼容好,适用于大部分需要透明图片的业务场景
48 | - webp压缩程度更好,在ios webview有兼容性问题,适用于安卓全部
49 | - svg矢量图,代码内嵌,相对较小,适用于图片样式相对简单的场景
50 | - 图片优化的几种方法,通常都用前端构建工具完成
51 | - 进行图片压缩,常用网站:[tinypng](https://tinypng.com/)
52 | - css雪碧图,常用网站:[spritecow](http://www.spritecow.com/)
53 | - 优点:减少HTTP请求量
54 | - 缺点:整合图片比较大时,一次加载比较慢
55 | - imgge inline 将图片的内容内嵌到html当中,图片要小才能适用这种方法
56 | - 适用矢量图
57 | - 适用SVG进行矢量图的绘制
58 | - 适用iconfont解决icon问题
59 | - 在安卓下使用webp,常用制作webp的网站:[智图](http://zhitu.isux.us/)
60 | ## css和js的装载与执行
61 | - html加载渲染的过程
62 |
63 | 
64 | - html渲染过程的一些特点
65 | - 顺序执行,并发加载
66 | - 是否阻塞
67 | - 依赖关系
68 | - 引入方式
69 | - css阻塞
70 | - css head中阻塞页面的渲染
71 | - css阻塞js的执行
72 | - css不阻塞外部脚本的加载
73 | - js阻塞
74 | - 直接引入的js阻塞页面的渲染
75 | - js不阻塞资源的加载
76 | - js顺序执行,阻塞后续js逻辑的执行
77 | ## 懒加载与预加载
78 | - 懒加载
79 | - 图片进入可视区域之后请求图片资源
80 | - 减少无效资源的加载
81 | - 并发加载的资源过多会阻塞js的加载,影响网站的正常使用
82 | - 预加载
83 | - 图片等静态资源在使用之前提前请求
84 | - 资源使用到时能存缓存中加载,提升用户体验
85 | - 预加载的几种方式
86 | - 使用img图片直接加载,display属性设置为none
87 | - 使用Image对象
88 | - 使用XMLHttpRequest对象
89 | - 预加载的库:[PreloadJs](http://www.createjs.cc/preloadjs/docs/modules/PreloadJS.html)
90 | - PreloadJs的简单使用
91 | - 引入PreloadJs
92 | ```
93 |
94 |
95 | ```
96 | - 新建my_preload.js文件
97 | - my_load.js文件中写入如下代码
98 | ```
99 | // LoadQueue是一个加载管理器,可以预先加载一个文件或者一个文件队列
100 | var queue = new createjs.LoadQueue(false);
101 |
102 | // 为事件添加你想要的监听事件
103 | queue.on("complete", handleComplete, this);
104 |
105 | // 或添加多个文件使用列表或一个清单定义使用 loadManifest
106 | queue.loadManifest([
107 | {id: "myImage", src:"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=996503075,3768564257&fm=200&gp=0.jpg"},
108 | {id: "myImage2", src:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4287850242,3208290927&fm=200&gp=0.jpg"}
109 | ]);
110 |
111 | function handleComplete() {
112 | var image = queue.getResult("myImage");
113 | document.body.appendChild(image);
114 | }
115 | ```
116 | - 浏览器中打开index.html页面
117 | ## 重绘和回流
118 | ### 回流
119 | - 什么是回流
120 | - 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这时就需要回流。
121 | - 什么情况下会产生回流
122 | - 当页面布局和几何属性改变时就需要回流
123 | - 触发页面重布局的属性
124 | - 盒子模型相关属性:width、height、padding、margin、display、border-width、border、min-height
125 | - 定位属性及浮动:top、bottom、left、right、position、float、clear
126 | - 改变节点内部文字结构:text-align、overflow-y、font-weight、overflow、font-family、line-height、vertival-align、white-space、font-size
127 | ### 重绘
128 | - 什么是重绘
129 | - 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局,如color,则称为重绘
130 | - 回流必定引起重绘,重绘不一定引起回流
131 | - 避免重绘、回流的的两种方法
132 | - 避免使用触发重绘、回流的CSS属性
133 | - 新建图层
134 | - 将频繁重绘、回流的DOM元素单独作为一个图层,那么这个DOM元素的重绘和回流的影响只会在这个图层中。
135 | - 缺点:图层过多会消耗大量的时间进行图层合成
136 | - Chrome创建图层的条件
137 | - 3D或透视b变换css属性(transform、perspective,will-change:transform)
138 | - 使用加速视频解码的``标签
139 | - 拥有3D上下文(WebGL)上下文或加速的2D上下文的`