前言

为什么要进行Web性能优化?

流量搜索转换率用户体验Amazon 发现每100ms延迟导致1%的销量损失

寻找性能瓶颈

  • 了解性能指标 - 多快才算快
  • 利用测量工具和APIs
  • 优化问题,重新测量(迭代)

性能优化指标和测量工具

行业标准

性能优化-加载

  • 理解加载瀑布图

  • 基于HAR存储于重建性能信息

  • 重要测量指标

  • 速度指数(Speed Index)4秒

  • TTFB 衡量请求到响应一共多少时间

  • 页面加载时间,页面加载完一共要用多久

  • 首次渲染 不能一直是白屏,然后在后来的某一刻突然都出来,要给用户一个渐进的体验,第一次出现内容的时间就是首次渲染很重要,让用户很快感觉到你的网站有内容出现了

性能优化-响应

  • 交互动作的反馈时间 : 交互的反馈要及时
  • 帧率FPS :60fps
  • 异步请求的完成时间:尽量在1秒内完成,完成不了加loading动画

优化模型

RAIL测量模型

什么是RAIL?

Response 响应 : 对于用户的响应

Animation 动画 : 对于用户动画的流畅

Idle 空闲 : 让浏览器有足够的空闲时间

Load 加载 : 给用户一个直观的体验

RAIL的目标

让良好的用户体验成为性能优化的目标

RAIL评估标准

相应:处理事件应在 50ms 以内完成

动画:每 10ms 产生一帧

空闲:尽可能增加空闲时间

加载:在 5s 内完成内容加载并可以交互

测量工具(需要外网)

  • Chrome DevRools 开发调试、性能评测
  • Lighthouse 网站整体质量评估
  • WebPageTest 多测试地点、全面性能报告

使用 WebPageTest 评估Web网站性能

在线进行网站分析

WebPageTest.org

waterfall chart 请求瀑布图

first view 首次访问

repeat view 二次访问

如何在本地部署WebPageTest工具

一、下载docker https://docs.docker.com/docker-for-windows/install/

二、在终端使用官方提供的docker镜像

docker pull webpagetest/server

docker pull webpagetest/agent

三、运行

docker run -d -p 4000:80 webpagetest/server

docker run -d -p 4001:80 --network=“host” -e “SERVER_URL=http://localhost:4000/work” -e “LOCATION=Test” webpagetest/agent

使用LightHouse分析性能

安装

npm install -g lighthouse

使用

lighthouse 加上你要测试的网站地址

在chrome DevTools 中使用

查看该文件有没有被使用 ctrl + shift + p

搜索Show Network request blocking

使用chrome DevTools分析性能

Audit(Lighthouse)

Throttling 调整网络吞吐

Performance 性能分析

Network 网络加载分析

性能相关APIs

常用的性能测量APIs

关键事件节点(Navigation Timing,Resource Timing)

网络状态(Network APIs)

客户端服务端协商(HTTP Client Hints) & 网页显示状态(UI APIs)

重要的时间节点

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
首次可交互时间: domInteractive - fetchStart
DOM Ready 时间: domContentLoadEventEnd - fetchStart
页面完全加载时间: loadEventStart - fetchStart
http 头部大小: transferSize - encodedBodySize
重定向次数:performance.navigation.redirectCount
重定向耗时: redirectEnd - redirectStart
// 计算一些关键的性能指标
window.addEventListener('load', (event) => {// Time to Interactivelet timing = performance.getEntriesByType('navigation')[0];console.log(timing.domInteractive);console.log(timing.fetchStart);let diff = timing.domInteractive - timing.fetchStart;console.log("TTI: " + diff);
})
// 观察长任务
const observer = new PerformanceObserver((list) => {for (const entry of list.getEntries()) {console.log(entry)}
})observer.observe({entryTypes: ['longtask']})
// 见面可见性的状态监听
let vEvent = 'visibilitychange';
if (document.webkitHidden != undefined) {// webkit prefix detectedvEvent = '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);
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
var type = connection.effectiveType;function updateConnectionStatus() {console.log("Connection type changed from " + type + " to " + connection.effectiveType);type = connection.effectiveType;
}connection.addEventListener('change', updateConnectionStatus);

代码优化

V8 编译原理

抽象语法树

源码 – 抽象语法树 – 字节码Bytecode – 机器码

编译过程会进行优化

运行时可能发生反优化

V8 代表性优化机制

脚本流 :下载超过30kb时,会下载同时解析

字节码缓存 :不同页面使用相同代码会使用缓存

懒解析:不解析函数内部,用的时候解析

const {performance, PerformanceObserver} = require('perf_hooks');const add = (a, b) => a+b;const num1 = 1;
const num2 = 2;performance.mark('start');for(let i = 0; i < 10000000; i++) {add(num1, num2);
}//发现类型转变会导致编译变慢
add(num1, 's');for(let i = 0; i < 10000000; i++) {add(num1, num2);
}performance.mark('end');const observer = new PerformanceObserver((list) => {console.log(list.getEntries()[0]);
})
observer.observe({entryTypes: ['measure']});performance.measure('测量1', 'start', 'end');

JavaScript优化

JavaScript 的开销和如何缩短解析时间

开销在哪里?

加载

解析&编译

执行

解决方案

Code splitting 代码拆分,按需加载

Tree shaking 代码减重

减少主线程工作量

避免长任务

避免超过 1KB 的行间脚本

使用rAF和rIC进行时间调度

Progressive Bootstrapping

可见不可交互 vs 最小可交互资源集

函数优化

函数的解析方式

  • lazy parsing 懒解析 vs eager parsing 饥饿解析

懒解析 :不解析函数内部,用的时候解析

饥饿解析:一次性都解析

//饥饿解析是在原函数在添加一队括号
export default () => {const add = (a, b) => a*b; // lazy parsing// const add = ((a, b) => a*b); // eager parsingconst num1 = 1;const num2 = 2;add(num1, num2);
}
//当压缩的时候往往会去掉这个括号,解决方案如下
  • 利用Optimize.js优化初次加载时间(github)

对象优化

对象优化可以做哪些?

以相同顺序初始化对象成员,避免隐藏类的调整

实例化后避免添加新属性

尽量使用Array代替 array-like 对象

避免读取超过数组的长度

避免元素类型转换

/* 1 */
class RectArea { // HC0constructor(l, w) {this.l = l; // HC1this.w = w; // HC2}
}const rect1 = new RectArea(3,4); // 创建了隐藏类HC0, HC1, HC2
const rect2 = new RectArea(5,6); // 相同的对象结构,可复用之前的所有隐藏类const car1 = {color: 'red'}; // HC0
car1.seats = 4; // HC1const car2 = {seats: 2}; // 没有可复用的隐藏类,创建HC2
car2.color = 'blue'; // 没有可复用的隐藏类,创建HC3/* 2 */
const car1 = {color: 'red'}; // In-object 属性
car1.seats = 4; // Normal/Fast 属性,存储在property store里,需要通过描述数组间接查找/* 3 */
Array.prototype.forEach.call(arrObj, (value, index) => { // 不如在真实数组上效率高console.log(`${ index }:${ value }`);
});const arr = Array.prototype.slice.call(arrObj, 0); // 转换的代价比影响优化小
arr.forEach((value, index) => {console.log(`${ index }:${ value }`);
});/* 4 */
function foo(array) {for (let i = 0; i <= array.length; i++) { // 越界比较if(array[i] > 1000) { // 1.沿原型链的查找 2.造成undefined与数进行比较console.log(array[i]); // 业务上无效、出错}    }
}/* 5 */
const array = [3, 2, 1]; // PACKED_SMI_ELEMENTSarray.push(4.4); // PACKED_DOUBLE_ELEMENTS

HTML优化

减少 iframes 使用

压缩空白符

避免节点深层级嵌套

避免使用 table 布局

删除注释

CSS&Javascript 尽量外链

删除元素默认属性

借助工具

html-minifier

CSS优化

CSS对性能的影响

样式计算开销

  • 利用DevTools测量样式计算开销

CSS优化

降低CSS对渲染的阻塞利用GPU进行完成动画利用contain属性使用font-display属性

渲染优化

现代浏览器渲染原理

当用户在浏览器输入一个地址,然后按回车后到这个页面显示之前,这期间经历了那些过程

无论是 js 还是 css 都是代码(文本),计算机理解不了文本,所以第一步要做什么?他要通过一些解释权把你这些文本翻译成他能理解的数据结构浏览器构造对象模型​    构造DOM对象 (内容)HTML -- DOM​    构建CSSOM对象(样式)​            CSS  -- CSSOM   接下来这俩颗树会进行合并称为(Render Tree)浏览器构建渲染树然后把真正需要留下的节点留下,不需要的去掉

关键渲染路径(critical rendering path)

JavaScript:触发视觉变化Style:重新对样式计算layout:布局(位置)Paint:绘制(画在页面上)Composite:合成(类似ps)

可优化的渲染环节和方法

布局(layouts)与绘制(paint)

渲染树只包含网页需要的节点布局计算每个节点精确的位置和大小-“盒模型”绘制是像素化每个节点的过程

影响回流的操作

当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。

  • 添加/删除元素
  • display:none
  • 移动元素位置
  • 操作styles
  • offsetLeft,scrollTop,clientWidth
  • 修改浏览器大小,字体大小

避免layout thrashing(布局抖动)

  • 避免回流
  • 读写分离

FastDom(防止布局抖动的利器 GitHub)

fastdom.measure(() => {console.log('measure');
});fastdom.mutate(() => {console.log('mutate');
});

复合线程(compositor thread)与图层(layers)

复合线程做什么

  • 复合不会发生布局和重绘
  • 将页面拆分图层进行绘制再进行复合
  • 利用DevTools了解网页的图层拆分情况
  • 哪些样式仅影响复合

减少重绘(加上页面呈现)

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。

高频 事件处理函数 防抖

如果短时间内大量触发同一事件,只会执行一次函数。

/*
* fn [function] 需要防抖的函数
* delay [number] 毫秒,防抖期限值
*/
function debounce(fn,delay){let timer = null //借助闭包return function() {if(timer){clearTimeout(timer) //进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时timer = setTimeout(fn,delay) }else{timer = setTimeout(fn,delay) // 进入该分支说明当前并没有在计时,那么就开始一个计时}}
}

React时间调度实现

资源优化

压缩&合并

为什么要压缩&合并?

减少http请求数量减少请求资源的大小

HTML压缩

使用在线工具进行压缩 http://kangax.github.io/html-minifier/使用html-minifier等npm工具

CSS压缩

使用在线工具进行压缩使用  clean-css 等 npm 工具 (上面网站集成了)

JS压缩与混淆

使用在线工具进行压缩使用webpack对JS在构建时压缩

CSS JS文件合并

若干小文件,maybe...无冲突,服务相同的模块,ok优化加载,NO

图片格式

图片优化的方案

选择一个正确地格式,不同的格式有不同的优缺点,使用特定的图片会有特定的优势图片的大小要选择合适,不要传一个过大的图片,然后在进行尺寸大小的调整要适配不同尺寸的屏幕压缩:根据你的网站需求,比如摄影类需要高清的图片,压缩的空间就会很小图片的优先级,重要的东西要优先加载懒加载:不需要把所有的图片都加载,用户看哪些加载哪些,或者预加载利用一些工具帮我们做这些事情

图片格式比较

JPEG/JPG的优点https://github.com/imagemin/imagemin 压缩图片网址
我们用的最多的图片格式,它是一种有损压缩的图片格式,压缩比高,色彩保存还好,色彩感好 JPEF/JPG的使用场景当想使用比较大的图片还想保存展现的画质效果JPEG/JPG的缺陷​因为压缩比高,所以边缘会很粗糙PNG 的优点​可以做透明背景的图片,最大的优点是弥补了JPEG/JPG的缺点PNG 的使用场景​做一下小的图片,图标,logo之类PNG 的缺陷​体积比较大WebP的优点​跟PNG 有一样的质量,压缩比例比PNG 高,有兼容性问题

图片加载

图片的懒加载(lazy loading)

  • 原生的图片懒加载方案
<img src=""  loading="lazy" alt="">
//需要浏览器支持,而且自定义和扩展性不强
  • 第三方图片懒加载方案(github)

    • verlok/lazyload
    <LazyLoadImageclassName={this.props.classes.media}src={this.props.image}effect="blur"rel="preconnect"
    />
    
    • yall.js
    • Blazy

使用渐进式图片

解决方案

progressive-imagelibjpegjpeg-recompressImageMagickjpegtranimagemin

使用响应式图片

我们需要在不同的屏幕上,都能适配

Srcset     属性的使用图片集:        路径加尺寸Sizes      属性的使用sizes="100vw"  指的是视窗宽度的百分比picture的使用

字体优化

什么是FOIT和FOUT

  • 字体未下载完成时,浏览器隐藏或自动降级,导致字体闪烁
  • Flash Of Invisible Text 文字从看不到到看到闪烁变化的过程
  • Flash Of Unstyled Text 开始是一种样式,后来结果渲染变为另外一种字体

使用font-display

AJAX + Base64

  • 解决兼容问题
  • 缺点:缓存问题

构建优化

webpack的优化配置

https://webpack.js.org/configuration/mode/

Tree-shaking(调成production webpack.config.js)

上下文未用到的代码(dead code)基于ES6 import export

它的局限性是基于ES6,模块化的语法
但是有时候我们会修改全局作用域,可能我们在全局在添加了方法或者属性,这个时候,如果他把这个东西给摇掉了,代码就会出错解决方案他给我们留了后门,我们可以通过一些方式告诉webpack
//package.json 把你认为有副作用的添加到
"sideEffects": ["*.css"]

JS压缩

Webpack 4 后引入 uglifyjs-webpack-plugin支持 ES6 替换为terser-webpack-plugin(生产模式下默认的)减少 JS 文件体积

作用域提升

代码体积减少提高执行效率同样注意Babel的modules配置
/****************** util.js ******************/
export default 'Hello,Webpack';/**************** index.jsx ********************/
import str from './util';
console.log(str);/***************** 没有 scope hoisting, webpack 打包后 *******************/
[(function (module, __webpack_exports__, __webpack_require__) {var __WEBPACK_IMPORTED_MODULE_0__util_js__ = __webpack_require__(1);console.log(__WEBPACK_IMPORTED_MODULE_0__util_js__["a"]);}),(function (module, __webpack_exports__, __webpack_require__) {__webpack_exports__["a"] = ('Hello,Webpack');})
]
/************************************//***************** 有 scope hoisting, webpack 打包后 *******************/
[(function (module, __webpack_exports__, __webpack_require__) {var util = ('Hello,Webpack');console.log(util);})
]
/************************************/

Babel7优化配置

在需要的地方引入 polyfill(兼容旧浏览器,做一下新的功能实现)关于Babel默认配置的影响辅助函数的按需引入设置默认浏览器
//babel.config.js
module.exports = {presets: [[//他会把es6的语法转为别的语法(默认)'@babel/preset-env',{//我们希望保留 es6 语法(默认)modules: false,//设置默认浏览器"targets": {//意思是要对超过市场份额超过百分之0.25的所有浏览器支持"browsers": [">0.25%"]},//通过这个配置就可以你需要的(polyfill)"useBuiltIns": "usage","bugfixes": true}],'@babel/preset-react'],plugins: ['@babel/plugin-proposal-class-properties',//辅助函数的按需引入"@babel/plugin-transform-runtime",]
};

依赖优化

无论我们的工程有多大,当我们使用webpack去打包的时候,总能得到一定的优化,但是webpack本身打包的过程有时候却有一些慢、

解决方案

noParse(不解析)

  • 提高构建速度
  • 直接通知 webpack 忽略较大的库
  • 被忽略的库不能有import,require,define的引用方式(传统方式)

把我们非常确信的,不需要解析的库添加到这里就可以

DllPlugin

把我们经常需要的重复的库给提取出来,变成一种引用的方式,这样不需要每一次都重新构架,大大加速了构建的过程

  • 避免打包时对不变的库重复构建,比如我们用react 写的那么react和react dom从开始到上线可能都不会变
  • 提高构建速度
// 新建文件webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {mode: "production",//入口entry: {//我希望我需要创建的文件叫react,他要包含的就是能需要创建动态链接库的类react: ["react", "react-dom"],},//输出output: {// name 取的是入口文件定义的名字filename: "[name].dll.js",// 路径把它放到一个叫dll的包,正常情况是没有的,正常运行之后会自动生成path: path.resolve(__dirname, "dll"),//库名称取入口名称library: "[name]"},plugins: [//我们就是通过DllPlugin帮我们去生成动态链接文件的描述文件new webpack.DllPlugin({//name和library: "[name]"一致name: "[name]",//和动态链接路径放到同样的路径下path: path.resolve(__dirname, "dll/[name].manifest.json")})]
};//运行
//在package.json下scripts中配置
"dll-build": "NODE_ENV=production webpack --config webpack.dll.config.js",npm run dll-build// 然后回到正常的webpack配置文件中在 plugins 下添加//引用
new DllReferencePlugin({manifest: require(`${__dirname}/dll/react.manifest.json`)
})

代码拆分

基于webpack的代码拆分

对应一个大型的应用来说,如果我们把所有的东西都放成一个包,那么是十分低效的,也是不可接受的,我们说如果打包是一个合的过程,那么我们现在就是拆。

webpack在默认情况下会把所有东西打成一个bundles文件(包),那我们要做的就是要吧这个包拆分成若干个小的bundles或者叫做chunks,也就是说我们要把大的东西拆分成小的东西,那么目的是什么?

缩短首屏加载时间:我们知道,如果把一个大的文件拆散了,然后把重要的东西先加载,达到一个快速的让首屏进行显示的效果的话,那么对用户的体验是一个极大的提升

Webpack 代码拆分的方法

  • 手工定义入口
// 在webpack.config.js中,添加不同的入口文件,就会打出多个包,缺点是公共部分会被多次打包
entry: {app: './src/index.jsx',// test: './src/test.js' // 测试函数lazy parsing, eager parsing
},
  • splitChunks 提取共有代码,拆分业务代码与第三方库(webpack的一个插件)
// 在webpack.config.js中有一个optimization节点,没有自行添加
optimization: {//我们在这个节点里直接可以使用splitChunkssplitChunks: {//因为我们要给他分组,使用我们用到一个cacheGroups//里面我们要做俩件事,第一件事把第三方库拆分到一个bundles//第二件事把公共的代码拆分到一个bundlescacheGroups: {vendor: {//名字name: 'vendor',//匹配规则test: /[\\/]node_modules[\\/]/,//最小的大小minSize: 0,//最小多少段minChunks: 1,//优先级priority: 10,//同步加载(静态或动态的引入方式)chunks: 'initial'},common: {name: 'common',test: /[\\/]src[\\/]/,//把静态动态都考虑chunks: 'all',minSize: 0,minChunks: 2}}}},
  • 动态加载

理解一下声明为动态加载

//静态
import { add } from './math';console.log(add(16,26));//动态 异步加载文件
import("./math").then(math => {console.log(math.add(16,26));
})

webpack提出的动态解决方案

//改变引入方式
// import Card from './Card';
// 用下面这种方式这个Card组件其实就变成了动态组件
const Card = lazy(() => import('./Card'));for (let i = 0; i < 100; i++) {cards.push(model.map(panel => (//然后我们利用react给我们提供的Suspense,因为异步加载时有过程的,如果他还没有加载完成这个组件的时候,我们可以给他一个fallback,作为一个临时的替代<Suspense fallback={<div>Loading...</div>}><Card key={panel.name} image={panel.image} title={panel.name}route={panel.route} description={panel.body}/></Suspense>)));}

资源压缩(minification)

Terser压缩JS(上面有说)
mini-css-extract-plugin压缩CSS
要安装mini-css-extract-plugin 提取cssoptimize-css-assets-webpack-plugin
//webpack.config.js 下plugins
new MiniCssExtractPlugin({//提前的css文件名filename: '[name].[contenthash].css',//拆分的css文件名chunkFilename: '[id].[contenthash:8].css',
}),
new OptimizeCssAssetsPlugin({cssProcessorPluginOptions: {//把css的注释全部去掉preset: ['default', {discardComments: {removeAll: true}}],},canPrint: true
}),
  • HtmlWebpackPlugin - minify 压缩HTML

持久化缓存

持久化缓存方案

  • 每个打包的资源文件有唯一的hash值
  • 修改后只有受影响的文件hash变化
  • 充分利用浏览器缓存
//加点.[hash]即可
output: {path: `${__dirname}/build`,filename: '[name].[hash].bundle.js',chunkFilename: '[name].[chunkhash:8].bundle.js'},

监测与分析

  • Stats 分析与可视化图
  • webpack-bundle-analyzer 进行体积分析
  • speed-measure-webpack-plugin 速度分析

Webpack Chart(可视化图)

优点是在线的,不需要在项目里安装什么东西https://alexkuz.github.io/webpack-chart/ 输入给的指令将生成的stats.json添加进去即可,我们这个图是自内向外读

source-map-explorer(体积分析)

可以进一步分析(npm安装)"analyze": "source-map-explorer 'build/*.js'"

这步完成之后呢,我们就去npm run build 然后npm run analyze

speed-measure-webpack-plugin(速度分析)

npm 安装 导入

const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');const smp = new SpeedMeasurePlugin();
//包裹起来
module.exports = smp.wrap({});

传输加载优化

GZip

GZip是我们用来网络资源压缩,我们来减少在网络上传输大小的技术,在网络的传输过程中进行实时的动态的压缩,GZip可以说是我们唯一可选择的技术

Nginx

http://nginx.org/en/download.html 下载好点击打开,命令行执行 nginx 打开浏览器,输入地址:http://localhost,访问页面,出现如下页面表示访问成功

接下来我的看一下我们打包完成的前段工程,我们可以看到webpack帮我们打包完成后把所有文件都放在了build目录下

//在nginx.conf 中配置 (下载nginx目录中)server {# 开启gzip on为开启,off为关闭gzip on;# 检查是否存在请求静态文件的gz结尾的文件,如果有则直接返回该gz文件内容,不存在则先压缩再返回gzip_static on;# 设置允许压缩的页面最小字节数,页面字节数从header头中的Content-Length中进行获取。# 默认值是0,不管页面多大都压缩。# 建议设置成大于10k的字节数,配合compression-webpack-plugingzip_min_length 10k;# 对特定的MIME类型生效,其中'text/html’被系统强制启用gzip_types text/javascript application/javascript text/css application/json;# Nginx作为反向代理的时候启用,开启或者关闭后端服务器返回的结果# 匹配的前提是后端服务器必须要返回包含"Via"的 header头# off(关闭所有代理结果的数据的压缩)# expired(启用压缩,如果header头中包括"Expires"头信息)# no-cache(启用压缩,header头中包含"Cache-Control:no-cache")# no-store(启用压缩,header头中包含"Cache-Control:no-store")# private(启用压缩,header头中包含"Cache-Control:private")# no_last_modefied(启用压缩,header头中不包含"Last-Modified")# no_etag(启用压缩,如果header头中不包含"Etag"头信息)# auth(启用压缩,如果header头中包含"Authorization"头信息)# any - 无条件启用压缩gzip_proxied any;# 请求加个 vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩gzip_vary on;# 同 compression-webpack-plugin 插件一样,gzip压缩比(1~9),# 越小压缩效果越差,但是越大处理越慢,一般取中间值gzip_comp_level 6;# 获取多少内存用于缓存压缩结果,‘16  8k’表示以8k*16 为单位获得。# PS: 如果没有.gz文件,是需要Nginx实时压缩的gzip_buffers 16 8k;# 注:99.99%的浏览器基本上都支持gzip解压了,所以可以不用设这个值,保持系统默认即可。gzip_http_version 1.1;
}

重新启动nginx 服务

KeepAilve(Nginx)

HTTP KeepAilve 可以帮我们对 TCP 链接进行复用,也就是说当我们和一台服务器进行了 TCP 服务建立连接之后,接下来的请求就不需要在去重复的请求了

keepalive_timeout 0; 不适用 KeepAilvekeepalive_timeout 65; 默认 65秒不使用断开连接;keepalive_requests 100; 计算,也就是能可以利用KeepAilve可以发送多少个请求,之后重新建立

HTTP缓存(Nginx)

我们使用 HTTP 缓存主要是为了提高重复访问时资源加载的速度

Cache-Control

第一个条件匹配的是htmlCache-Control 让是HTTP1.1的一个标准,俩个参数实际上是要告诉浏览器,能不需要在你那端缓存,如果你需要这个文件,你就去服务端进行重新获取,然后获取完去重新验证后面俩个是为了兼容性,因为可能有老的浏览器他可能不支持第二个条件匹配的是js和css7天(让他从缓存里读)第三类是图片和静态资源7天(让他从缓存里读)

ETag

html资源文件的唯一标识,当我们设置缓存后实际上浏览器还是会请求服务端,然后服务端会会判断标识是否匹配,
匹配返回304 Not Modified 说明没有发生变化,不匹配就拿新数据JSCSS 如果你不强制请求,7天之内始终都是缓存中取的

Servive Workers

作用

  • 加速重复访问
  • 离线支持

原理

兼容性

只能在 localhost 或 https 下使用,部分浏览器不支持

HTTP/2(Nginx)(适合较高的请求量)

必须是https

# HTTPS server
#
#server {
#    listen       443 ssl;
#    server_name  localhost;
//证书
#    ssl_certificate      cert.pem;
#    ssl_certificate_key  cert.key; #    ssl_session_cache    shared:SSL:1m;
#    ssl_session_timeout  5m;#    ssl_ciphers  HIGH:!aNULL:!MD5;
#    ssl_prefer_server_ciphers  on;#    location / {
#        root   html;
#        index  index.html index.htm;
#    }
#}

SSH(自签名证书)

openssl genrsa -des3 -passout pass:x -out server.pass.key 2048openssl rsa -passin pass:x -in server.pass.key -out server.key openssl req -new -key server.key -out server.csr openssl x509 -req -sha256 -days 3650 -in server.csr -signkey server.key -out server.crt

访问

https://localhost:443

会有证书验证的信息,这个时候我们什么都不用点击 直接键盘输入 thisisunsafe

HTTP2 的优势

  • 多路复用

  • 服务器推送(servers push)
 location / {root   html;index  index.html index.html  我们可以使用http_push通过servers push 提前推送到服务器http2_push /img/me0.jpg;http2_push /img/me1.jpg;http2_push /img/me2.jpg;}

可以看到前三张没有绿色的条,也就是没有ttfb

服务端渲染SSR

SSR的好处

  • 加速首屏优化
  • 更好的SEO

更多流行优化技术

SVG优化图标

从 PNG 到 IconFont

IconFont的优势

多个图标  ----------  一套字体,减少获取时的请求数量和体积矢量图形,可伸缩直接通过 CSS 修改样式(颜色,大小等)

IconFont缺点

颜色单一性

从 IconFont到 SVG

SVG优势

保持了图片能力,支持多色彩独立的矢量图形XML语法,搜索引擎SEO和无障碍读屏软件读取

FlexBox布局

优势

更高性能的实现方案容器有能力决定子元素的大小,顺序,对齐,间隔等。双向布局

预加载

优化资源加载的顺序

资源优先级

  • 浏览器默认安排资源加载优先级

为什么要调整优先级?

因为我们觉得他默认安排的优先级不合适,我们通过调整可以做到优化

怎么去调整?

使用 preload,prefetch调整优先级

// Preload:提前加载较晚出现,但对当前页面非常重要的资源
// type="font/woff2(进一步类型)" crossorigin="anonymous(字体要跨域,必须设置这个属性)"<link rel="preload" href="img/product2.svg地址" as="image类型" >// Prefetch:提前加载后续页面需要的资源,优先级低<link rel="prefetch" href="img/product2.svg地址" as="image类型" >

预渲染

npm install -D react-snap//package.json
//在打包完成之后,自动触发postbuild
"postbuild": "react-snap"//使用ReactDOM.hydrate()//内联样式,避免明显的FOUC(样式闪动)

预渲染的作用

  • 大型单页应用的性能瓶颈:JS下载+解析+执行

  • SSR的主要问题:牺牲TTFB来补救First Paint;实现复杂

  • Pre-rendering 打包时提前渲染页面,没有服务端参与

    窗口化提高列表性能

    Windowing(窗口化)提高列表性能

    声明是Windowing?

    我们通常一个表格里有很多行,但是我们这个表格给用户看到的时候往往是只有其中的一部分,因为我们这些行不可能都展示给用户,所以我们有一个想法,我们能不能只渲染用户看见的这些行,如果是看不到的,我们就先不渲染,如果已经看过去的我们就立即把它回收掉。

    windowing的作用

    • 加载大列表、大表单的每一行严重影响性能
    • Lazy loading仍然会让DOM 变得过大
    • windowing只渲染可见的行,渲染和滚动的性能都会提升

骨架组件

使用骨架组件减少布局移动(Layout Shift)

Skeleton/Placeholder的作用

  • 占位
  • 提升用户感知性能

前端项目性能优化(全面解析)相关推荐

  1. 如何优化WebAPP性能:从五个层面上彻底优化前端项目性能

    如何优化WebAPP性能:从五个层面上彻底优化前端项目性能 资源层面上的优化 该项措施可以帮助我们优化 FP.FCP.LCP 指标. 压缩文件.使用 Tree-shaking 删除无用代码 服务端配置 ...

  2. 如何优化WebAPP性能:从四个层面上彻底优化前端项目性能

    如何优化WebAPP性能:从四个层面上彻底优化前端项目性能 资源层面上的优化 该项措施可以帮助我们优化 FP.FCP.LCP 指标. 压缩文件.使用 Tree-shaking 删除无用代码 服务端配置 ...

  3. vue项目性能优化——断点续传

    vue项目性能优化 用户上传文件的时候,如果文件过大,那么上传可能就会很耗时.而且一旦上传的过程中发生了网络中断,那上传就前功尽弃了.为了提高用户的体验,我们可以选择断点续传,也就是把文件切分成小块后 ...

  4. 项目性能优化之性能问题分析和压力测试

    项目性能优化之性能问题分析和压力测试 性能问题分析 为什么要性能优化 影响性能的关键要素 性能优化出发点 性能压力测试 什么是压力测试 压力测试的指标 常用压测工具 性能问题分析 为什么要性能优化 应 ...

  5. 前端页面性能优化 - 字体加载优化

    相比于英文的字库来说,中文字库的体积非常之大,小则1M,动辄几十 M 的体积非常常见.所以在前端页面性能优化中,字体加载的优化就显得尤为重要.阅读了相关的知识和文章,在研究了市面上字体加载方案之后,我 ...

  6. 前端页面性能优化指标

    前端页面性能优化指标 一.有哪些指标 LCP(Largest Contentful Paint) FID( First Input Delay) CLS(Cumulative Layout Shift ...

  7. 前端页面性能优化(完整归纳版)

    前端页面性能优化 当优化前端页面性能时,可以从多个方面入手.以下是一些常见的优化技巧,使用 Markdown 格式展示: 1. 优化资源加载 压缩和合并文件:减少请求次数,通过压缩和合并 CSS.Ja ...

  8. web前端页面性能优化小结

    一.提倡前端开发工程师在书写xhtml的时候做到结构语义化. 结构中主要包括了head和body两个部分,但是我们经常说的是结构语义化主要是body中的标签,但是我在这里还是简单的说一下head,he ...

  9. 欢乐互娱庞池海:《龙之谷》项目性能优化经验分享

    欢乐互娱庞池海:<龙之谷>项目性能优化经验分享 在5月12日,UNITY 2017案例分享专场上,欢乐互娱技术引擎开发工程师娱庞池海分享了<龙之谷>项目性能优化经验.以下为分享 ...

最新文章

  1. php 许愿墙 阶段案例_房地产全周期设计管控流程解析及跨部门合作及案例分析...
  2. flash TweenMax用法
  3. 【Linux 内核】调度器 ⑤ ( put_prev_task、set_next_task 函数 | select_task_rq 函数 | migrate_task_rq 函数 )
  4. java下载pdf6_疯狂java讲义第6版 电子版(pdf格式)
  5. Arduino笔记-外部中断实验(震动传感器实时亮灯)
  6. 开放app开放login_开放值得付出努力吗?
  7. ubuntu14.10 linux-header更新,Ubuntu 14.04 怎样升级到 Ubuntu 14.10
  8. LeetCode(1009)——十进制整数的反码(JavaScript)
  9. 【公众号系列】站在烦恼里仰望幸福
  10. mysql adodb_指南从MySQL转向ADODB的方法_MySQL
  11. jquery实现进度条
  12. Hugo Travis
  13. 计算机dvd驱动错误,修正:一个错误发生在弹出的CD/DVD驱动器在Windows 10
  14. 你不知道的接近开关与PLC连接时如何判断用PNP还是NPN
  15. Linux 脚本部署应用宝,应用宝新版继续整合资源,腾讯移动分发再加力
  16. 华为云服务怎么弄金卡会员_华为云XR云服务,助力千行百业产业升级
  17. k8s教程(基础篇)-基本概念和术语
  18. 孙陶然:成功者都不找借口
  19. Xib与Nib区别联系
  20. 浙大第四版概率论第一章思维导图

热门文章

  1. 智能手表遭遇“幽灵堵车”,华为、华米、苹果谁能争第一
  2. 记录一下 Android onCreate()、onStart()、onResume()、onDestory()、onStop()、onPause()什么时候执行
  3. tensorflow学习--sess.run()
  4. 微信小程序 使用animate动画教程
  5. C#通过Spire.OCR读取图片文字
  6. tiny4412 驱动 (15)解决DMA的问题
  7. 为Windows系统替换优雅的苹方,好看的OPPO字体
  8. 公司注销了怎么迁移公众号?
  9. linux创建只读共享目录,mkdir: 无法创建目录kk: 只读文件系统
  10. vue input或者el-input苹果软键盘换行变成发送 安卓软键盘开始变成发送