├── 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 | ![浏览器的一个请求从发送到返回的经历](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/6FEF241D4A474A709524227E7D6BD7D4/17830) 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 | ![html加载渲染的过程](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/E6F38972BFD34E89981B448423399DB9/17832) 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上下文的``节点 140 | - 混合插件(如Flash) 141 | - 对自己的opatity做css动画或使用一个动画webkit变换的元素 142 | - 拥有加速css过滤器的元素 143 | - 元素有一个包含复合层的后代节点(一个元素拥有一个子元素,该子元素在自己的层里) 144 | - 元素有一个z-index较低且包含一个复合层的兄弟元素,换句话说就是该元素在复合层上面渲染 145 | 146 | - 针对重绘、回流优化的方法 147 | - 用translate替代top改变,top会触发layout,translate不触发回流 148 | - 用opacity替代visibility,visibility触发重绘,opacity不会触发重绘 149 | - 不要一条条修改DOM样式,预先定义好class,然后修改DOM的className 150 | - 把DOM离线后修改,比如把DOM给display:none,然后你修改100次,然后再把它显示出来 151 | - 不要把DOM节点的属性值放在一个循环里当成循环里的变量,如offsetHeight、offsetWidth 152 | - 不要使用table布局,可能一个很小的改动会造成整个table的重新布局 153 | - 动画实现的速度的选择 154 | - 对于动画新建图层 155 | - 启用GPU硬件加速 156 | ## 浏览器存储 157 | ### cookies 158 | - 为什么需要cookies 159 | - 浏览器端和服务器端的交互,因为HTTP请求无状态,需要cookie维持客户端状态(设计初衷) 160 | - 客户端自身数据的存储 161 | 162 | ![cookies](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/9EDFA49A7D514C26996684524B5F3A98/17834) 163 | 164 | - cookie的生成方式 165 | - http response header中的set-cookie,服务端生成客户端存储和维护 166 | - js中可以通过document.cookie可以读写cookie 167 | - cookie存储限制 168 | - 作为浏览器存储,大小4kb左右 169 | - cookie是一个域名维度下的概念,只要是这个域名下的所有请求都会携带上cookie,但并不是所有请求都需要用cookie 170 | - 解决办法:cdn上放静态文件,cdn的域名和主站的域名要分开,每次请求cdn静态文件不会携带上cookie 171 | - 需要设计过期时间 expire 172 | - cookie的一个重要属性httponly,不允许js读写 173 | - cookie的简单操作 174 | ``` 175 | //设置cookie 176 | document.cookie = "username=jerry"; 177 | document.cookie = "age=18"; 178 | //读取cookie 179 | console.log(document.cookie);//username=jerry; age=18; 180 | ``` 181 | 注意:在谷歌浏览器chrome中调试居然不生效!!!不管是使用jquery的cookie插件,还是js原生态的cookie方法都不生效!!!什么原因呢?原因在于chrome不支持js在本地操作cookie! 182 | ### LocalStorage 183 | - 特点: 184 | - HTML5设计出来专门用于浏览器存储的 185 | - 大小5M左右 186 | - 仅在客户端使用,不和服务端进行通信 187 | - 接口封装较好 188 | - 浏览器本地缓存方案 189 | - 简单使用 190 | ``` 191 | if (window.localStorage){ 192 | // 设置localStorage 193 | localStorage.setItem('age', '18'); 194 | localStorage.setItem('name', 'ffy'); 195 | // 读取localStorage中的值 196 | console.log(localStorage.getItem('name')); 197 | console.log(localStorage.getItem('age')); 198 | } 199 | ``` 200 | ### SessionStorage 201 | - 特点: 202 | - 会话级别的浏览器存储 203 | - 大小5M左右 204 | - 仅在客户端使用,不和服务端进行通信 205 | - 接口封装较好 206 | - 对于表单信息的维护 207 | - 简单使用 208 | ``` 209 | if (window.sessionStorage){ 210 | // 设置SessionStorage 211 | sessionStorage.setItem('name', 'yff'); 212 | sessionStorage.setItem('score', '100'); 213 | // 读取SessionStorage中的值 214 | console.log(sessionStorage.getItem('name')); 215 | console.log(sessionStorage.getItem('score')); 216 | } 217 | ``` 218 | ### IndexDB 219 | IndexDB是一种低级API,用户客户端存储大量结构化数据。该API使用索引来实现对该数据的高性能搜索。虽然Web Storage对于存储较少量的数据很有用,但对于存储大量的结构化数据来说,这种方法不太适用,IndexDB提供了一个解决方案 220 | ### Service Workers 221 | - 什么是Service Workers 222 | - Service Worker是一个脚本,浏览器独立于当前网页,将其在后台运行,为实现一些不依赖页面或者用户交互的特性打开了一扇大门。在未来这些特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),但它将推出的第一个首要特性,就是拦截和处理网络请求的能力,包括以编程方式来管理被缓存的响应。 223 | - chrome://serviceworker-internals/运行过的Service Workers 224 | - chrome://inspect/#service-workers查看浏览器正在运行的Service Workers 225 | - 生命周期 226 | 227 | ![Service Workers生命周期](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/3A42973E48174043BA1849D2EF3F68F6/17836) 228 | ### PWA 229 | - 什么是PWA 230 | - PWA(Progressive Web Apps)是一种Web App新模型,并不是具体指某一种前沿的技术或者某一个单一的知识点,我们从英文缩写来看就能看出来,这是一个渐进式的Web App,是通过一系列新的Web特性,配合优秀的UI交互设计,逐步增强Web App的用户体验。 231 | - PWA的三个方向 232 | - 可靠:在没有网络的环境中也能提供基本的页面访问,而不会出现"未连接到互联网"的页面 233 | - 快速:针对网页渲染及网络数据访问有较好优化 234 | - 融入:应用可以被添加到手机桌面,并且和普通应用一样有全屏、推送等特性 235 | - PWA性能检测[Chrome插件-lighthouse](https://lavas.baidu.com/doc-assets/lavas/vue/more/downloads/lighthouse_2.1.0_0.zip) 236 | ## 缓存 237 | - Expires 238 | - 缓存过期时间,用来指定资源到期时间,是服务器端的具体的时间点。 239 | - 告诉浏览器在过期时间前浏览器可以直接从浏览器缓存读取数据,无需再次请求 240 | - Cache-Control 241 | - max-age:指定缓存的最大有效时间 242 | - s-maxage:只能指定public的缓存设备,比如cdn,开放给不同人使用的设备 243 | - private:表示响应是针对单个用户,不能由共享缓存存储。私有缓存可以存储响应。 244 | - public: 表示响应可能被任何缓存缓存 245 | - no-cache:不管怎么样都会发起请求,询问缓存是否过期 246 | - no-store:所有内容都不会被缓存到缓存或 Internet 临时文件中 247 | - last-modified和If-modified-since 248 | - 基于客户端和服务端协商的缓存机制 249 | - last-modified--response header 250 | - If-modified-since-- request header 251 | - 需要和Cache-Control共同使用,如果max-age过期了才会和服务端进行协商 252 | - last-modified的缺点 253 | - 某些服务端不能获取精确的修改时间,用last-modified返回准确时间是做不到的 254 | - 文件修改时间改了,但文件内容没有变,这种情况使用last-modified也会让缓存失效,这样是不合理的 255 | 256 | - Etag-If-None-Match 257 | - 文件内容的hash值 258 | - etag -- response header 259 | - if-none-match -- request header 260 | - 需要与cache-control共同使用 261 | - 分级缓存策略 262 | 263 | ![分级缓存策略](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/A797B68940C94518932A2C86B568BCFC/17838) 264 | 265 | - 查看chrome浏览器当前缓存的信息:chrome://cache/ 266 | - chrome直接刷新都会在 Request header中加一个Cache-Control:max-age=0 267 | 268 | #### 遇到的问题 269 | 在用node配置环境测试缓存时,一启动服务就报 `Cannot find module 'mime'`,mime是我自定义的js文件,然后将它在app.js中用require引用:`mime = require('mime');`,感觉哪都没错呀,为什么报这个错误呢?仔细过了遍代码发现mine的引用前少了./,将代码改为`mime = require('./mime');`后,程序运行完美。 270 | ## SSR(服务端渲染) 271 | ### 272 | ## 传说中的彩蛋: 273 | 274 | - MAC OSX右键菜单能否添加类似于“在终端中打开当前目录”的快捷方式? 275 | 276 | 系统偏好设置 -> 键盘 -> 快捷键 -> 服务,勾选「新建位于文件夹位置的终端窗口」(后面的键盘快捷键可以不选),然后在 Finder 里面选中文件夹右键菜单的「服务」下面就会有「新建位于文件夹位置的终端窗口」这一子菜单了。 277 | - MAC OS快速打开spotlight 278 | ``` 279 | Control 键+空格 280 | ``` 281 | Command+B立刻打开网页在搜索引擎中搜索你键入OS快速打开spotlight的内容。 282 | - 使用VSCode编辑markdown使用到的插件 283 | - [Markdown Preview Mermaid Support](https://shd101wyy.github.io/markdown-preview-enhanced/#/zh-cn/) 显示流程图用,Markdown Preview Enhanced 使用 mermaid 来渲染流程图和时序图。 284 | - Markdown Preview Enhanced 是一款为 Atom 以及 Visual Studio Code 编辑器编写的超级强大的 Markdown 插件 285 | - diff语法,版本控制的系统中都少不了diff的功能,即展示一个文件内容的增加与删除,使用绿色表示新增,红色表示删除。其语法与代码高亮类似,只是在三个反引号后面写diff, 并且其内容中,以 +开头表示新增,-开头表示删除。 286 | ```diff 287 | + test 288 | - test 289 | ``` 290 | - [git commit时使用Emoji](https://gitmoji.carloscuesta.me/) 291 | 使用方法:直接复制上述网址中所需图片下面黑色粗体文字到commit的描述中即可 292 | ``` 293 | git commit -m ':art:格式化代码' 294 | ``` 295 | ## 相关技术和工具 296 | - 少量Vue.js 297 | - 版本控制:git 298 | - 开发工具:VSCode 299 | - 调试工具:Chrome 300 | - performance 301 | - layers 302 | ## 下载源码 303 | ``` 304 | git clone https://github.com/fangfeiyue/Web_Performance_Optimization.git 305 | ``` 306 | ## 运行项目 307 | ``` 308 | npm install 309 | npm run dev 310 | ``` 311 | ## 说明 312 | 如果对您有帮助,您可以点右上角 "Star" 支持一下 谢谢! ^_^ 313 | 314 | 或者您可以 "follow" 一下,我会不断开源更多的有趣的项目 315 | ## 个人简介 316 | 作者:房飞跃 317 | 318 | 博客地址:[前端网](http://www.qdfuns.com/house/31986/note) [博客园](https://www.cnblogs.com/fangfeiyue) [GitHub](https://github.com/fangfeiyue) 319 | 320 | 职业:web前端开发工程师 321 | 322 | 爱好:探索新事物,学习新知识 323 | 324 | 座右铭:一个终身学习者 325 | 326 | ## 联系方式 327 | 坐标:北京 328 | 329 | QQ:294925572 330 | 331 | 微信: 332 | 333 | ![XinShiJieDeHuHuan](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/100D55934BB446839482D3EA0CDC3E8D/17820) 334 | 335 | ## 赞赏 336 | 觉得有帮助可以微信扫码支持下哦,赞赏金额不限,一分也是您对作者的鼎力支持 337 | 338 | ![微信打赏](http://note.youdao.com/yws/public/resource/c2361265179a03449f6d52397fd50033/xmlnote/D77744C8EC944CF6AA232272CBC5CF6D/17828) --------------------------------------------------------------------------------