拯救你的年底 KPI:前端性能优化
前言
性能优化
,每个工程师跑不掉的一个话题。这里是本人总结的一些优化手法,希望对大家有所帮助,感谢各位大哥????
演示demo
在线预览: http://118.25.49.69:8085/
fe-optimize 源码: https://github.com/alexwjj/fe-optimize
演示PPT
在线预览:http://118.25.49.69:8086/
fe-ppt 使用HTML做的PPT源码
前端性能的影响(长篇大论警告❗️❗️❗️)
前端性能的一个重要指标是页面加载时间,不仅事关用户体验,也是搜索引擎排名考虑的一个因素。
来自Google的数据表明,一个有10条数据0.4秒能加载完的页面,变成30条数据0.9秒加载完之后,流量和广告收入下降90%。
Google Map 首页文件大小从100KB减小到70-80KB后,流量在第一周涨了10%,接下来的三周涨了25%。
亚马逊的数据表明:加载时间增加100毫秒,销量就下降1%。所以:重铸性能之光,我辈义不容辞????
一、调试工具
磨刀不误砍柴工,读完大学再打工!
1、Network
这里可以看到资源加载详情,初步评估影响页面性能的因素。鼠标右键可以自定义选项卡,页面底部是当前加载资源的一个概览。DOMContentLoaded DOM渲染完成的时间,Load:当前页面所有资源加载完成的时间
#思考:如何判断哪些资源对当前页面加载无用,做对应优化?shift + cmd + P 调出控制台的扩展工具,添加规则
扩展工具 更多使用姿势
#瀑布流waterfall
Queueing 浏览器将资源放入队列时间
Stalled 因放入队列时间而发生的停滞时间
DNS Lookup DNS解析时间
Initial connection 建立HTTP连接的时间
SSL 浏览器与服务器建立安全性连接的时间
TTFB 等待服务端返回数据的时间
Content Download 浏览器下载资源的时间
2、Lighthouse
First Contentful Paint 首屏渲染时间,1s以内绿色
Speed Index 速度指数,4s以内绿色
Time to Interactive 到页面可交换的时间
根据chrome的一些策略自动对网站做一个质量评估,并且会给出一些优化的建议。
3、Peformance
对网站最专业的分析~后面会多次讲到
4、webPageTest
可以模拟不同场景下访问的情况,比如模拟不同浏览器、不同国家等等,在线测试地址:webPageTest
5、资源打包分析
#webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer
// webpack.config.js 文件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports={plugins: [new BundleAnalyzerPlugin({analyzerMode: 'server',analyzerHost: '127.0.0.1',analyzerPort: 8889,reportFilename: 'report.html',defaultSizes: 'parsed',openAnalyzer: true,generateStatsFile: false,statsFilename: 'stats.json',statsOptions: null,logLevel: 'info'}),]
}// package.json
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
#开启source-mapwebpack.config.js
module.exports = {mode: 'production',devtool: 'hidden-source-map',
}
package.json
"analyze": "source-map-explorer 'build/*.js'",
npm run analyze
二、WEB API
工欲善其事,必先利其器。浏览器提供的一些分析API至关重要
1、监听视窗激活状态
大学都刷过慕课吧?只要离开窗口视频就会暂停~
或者一些考试网站,提醒你不能离开当前窗口
再或者,这种效果~
// 窗口激活状态监听
let vEvent = 'visibilitychange';
if (document.webkitHidden != undefined) {vEvent = 'webkitvisibilitychange';
}function visibilityChanged() {if (document.hidden || document.webkitHidden) {document.title = '客官,别走啊~'console.log("Web page is hidden.")} else {document.title = '客官,你又回来了呢~'console.log("Web page is visible.")}
}document.addEventListener(vEvent, visibilityChanged, false);
其实有很多隐藏的api,这里大家有兴趣的可以去试试看:
2、观察长任务(performance 中Task)
const observer = new PerformanceObserver((list) => {for (const entry of list.getEntries()) {console.log(entry)}
})observer.observe({entryTypes: ['longtask']})
3、监听网络变化
网络变化时给用户反馈网络问题,有时候看直播的时候自己的网络卡顿,直播平台也会提醒你或者自动给你切换清晰度
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);
4、计算DOMContentLoaded时间
window.addEventListener('DOMContentLoaded', (event) => {let timing = performance.getEntriesByType('navigation')[0];console.log(timing.domInteractive);console.log(timing.fetchStart);let diff = timing.domInteractive - timing.fetchStart;console.log("TTI: " + diff);
})
5、更多计算规则
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
三、老生常谈,雅虎军规
磨好刀了,就该想想往哪里捅比较好了~ ????????????
关于雅虎军规,你知道的有多少条,平时写用到的又有哪些?针对以下规则,我们可以做很多优化工作
1、减少cookie传输
cookie传输会造成带宽浪费,可以:
减少cookie中存储的东西 静态资源不需要cookie,可以采用其他的域名,不会主动带上cookie。
2、避免过多的回流与重绘
连续触发页面回流操作
let cards = document.getElementsByClassName("MuiPaper-rounded");const update = (timestamp) => {for (let i = 0; i <cards.length; i++) {let top = cards[i].offsetTop;cards[i].style.width = ((Math.sin(cards[i].offsetTop + timestamp / 100 + 1) * 500) + 'px')}window.requestAnimationFrame(update)}update(1000);
看下效果,很明显的卡顿
performance分析结果,load事件之后存在大量的回流,并且chrome都给标记了红色
使用fastDom进行优化,将对dom的读和写分离,合并
let cards = document.getElementsByClassName("MuiPaper-rounded");const update = (timestamp) => {for (let i = 0; i < cards.length; i++) {fastdom.measure(() => {let top = cards[i].offsetTop;fastdom.mutate(() => {cards[i].style.width =Math.sin(top + timestamp / 100 + 1) * 500 + "px";});});}window.requestAnimationFrame(update)}update(1000);
再看下效果,很流畅~
performance分析结果,load事件之后也没有了那么多的红色标记
感兴趣的可以去了解一下fastDom:github fastdom 在线预览:fastdom demo
关于任务拆分与组合的思想,react fiber架构做的很牛逼,有兴趣的可以去了解一下调度算法在fiber中的实践
四、压缩
嗯哼哼、确定一下没有走错场子,继续继续!
1、Gzip
开启方式可参考:nginx开启gzip
还有一种方式:打包的时候生成gz文件,上传到服务器端,这样就不需要nginx来压缩了,可以降低服务器压力。可参考:gzip压缩文件&webPack配置Compression-webpack-plugin
2、服务端压缩
server.jsconst express = require('express');
const app = express();
const fs = require('fs');
const compression = require('compression');
const path = require('path');app.use(compression());
app.use(express.static('build'));app.get('*', (req,res) =>{res.sendFile(path.join(__dirname+'/build/index.html'));
});const listener = app.listen(process.env.PORT || 3000, function () {console.log(`Listening on port ${listener.address().port}`);
});
package.json"start": "npm run build && node server.js",
3、JavaScript、Css、Html压缩
工程化项目中直接使用对应的插件即可,webpack的主要有下面三个:
UglifyJS webpack-parallel-uglify-plugin terser-webpack-plugin 具体优缺点可参考:webpack常用的三种JS压缩插件。压缩原理简单的讲就是去除一些空格、换行、注释,借助es6模块化的功能,做了一些tree-shaking的优化。同时做了一些代码混淆,一方面是为了更小的体积,另一方面也是为了源码的安全性。css压缩主要是mini-css-extract-plugin,当然前面的js压缩插件也会给你做好css压缩。使用姿势:
npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
plugins:[new MiniCssExtractPlugin({filename: "[name].css",chunkFilename: "[id].css"})
]
html压缩可以用HtmlWebpackPlugin,单页项目就一个index.html,性能提升微乎其微~
4、http2首部压缩
http2的特点
二进制分帧 首部压缩 流量控制 多路复用 请求优先级 服务器推送http2_push: 'xxx.jpg' 具体升级方式也很简单,修改一下nginx配置,方法请自行Google
五、webpack优化
上文中也提到了部分webpack插件,下面我再来看看还有哪些~
1、DllPlugin 提升构建速度
通过DllPlugin插件,将一些比较大的,基本很少升级的包拆分出来,生成xx.dll.js文件,通过manifest.json引用
webpack.dll.config.jsconst path = require("path");
const webpack = require("webpack");
module.exports = {mode: "production",entry: {react: ["react", "react-dom"],},output: {filename: "[name].dll.js",path: path.resolve(__dirname, "dll"),library: "[name]"},plugins: [new webpack.DllPlugin({name: "[name]",path: path.resolve(__dirname, "dll/[name].manifest.json")})]
};
package.json"scripts": {"dll-build": "NODE_ENV=production webpack --config webpack.dll.config.js",},
#2、splitChunks 拆包
optimization: {splitChunks: {cacheGroups: {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}}}},
六、骨架屏
用css提前占好位置,当资源加载完成即可填充,减少页面的回流与重绘,同时还能给用户最直接的反馈。图中使用插件:react-placeholder
关于实现骨架屏还有很多种方案,用Puppeteer服务端渲染的挺多的
使用css伪类:只要css就能实现的骨架屏方案
等等
七、窗口化
原理:只加载当前窗口能显示的DOM元素,当视图变化时,删除隐藏的,添加要显示的DOM就可以保证页面上存在的dom元素数量永远不多,页面就不会卡顿
图中使用的插件:react-window
安装:npm i react-window
引入:import { FixedSizeList as List } from 'react-window';
使用:
const Row = ({ index, style }) => (<div style={style}>Row {index}</div>
);const Example = () => (<Listheight={150}itemCount={1000}itemSize={35}width={300}>{Row}</List>
);
八、缓存
1、http缓存
keep-alive
判断是否开启:看response headers中有没有Connection: keep-alive 。
开启以后,看network的瀑布流中就没有 Initial connection耗时了
nginx设置keep-alive(默认开启)
#0 为关闭
#keepalive_timeout 0;
#65s无连接 关闭
keepalive_timeout 65;
#连接数,达到100断开
keepalive_requests 100;
Cache-Control / Expires / Max-Age 设置资源是否缓存,以及缓存时间
Etag / If-None-Match 资源唯一标识作对比,如果有变化,从服务器拉取资源。如果没变化则取缓存资源,状态码304,也就是协商缓存
Last-Modified / If-Modified-Since 通过对比时间的差异来觉得要不要从服务器获取资源
更多HTTP缓存参数可参考:使用 HTTP 缓存:Etag, Last-Modified 与 Cache-Control
2、Service Worker
借助webpack插件WorkboxWebpackPlugin和ManifestPlugin,加载serviceWorker.js,通过serviceWorker.register()注册
new WorkboxWebpackPlugin.GenerateSW({clientsClaim: true,exclude: [/\.map$/, /asset-manifest\.json$/],importWorkboxFrom: 'cdn',navigateFallback: paths.publicUrlOrPath + 'index.html',navigateFallbackBlacklist: [new RegExp('^/_'),new RegExp('/[^/?]+\\.[^/]+$'),],
}),new ManifestPlugin({fileName: 'asset-manifest.json',publicPath: paths.publicUrlOrPath,generate: (seed, files, entrypoints) => {const manifestFiles = files.reduce((manifest, file) => {manifest[file.name] = file.path;return manifest;}, seed);const entrypointFiles = entrypoints.app.filter(fileName => !fileName.endsWith('.map'));return {files: manifestFiles,entrypoints: entrypointFiles,};},
}),
九、预加载 && 懒加载
1、preload
就拿demo中的字体举例,正常情况下的加载顺序是这样的:
加入preload:
2、prefetch
场景:首页不需要这样的字体文件,下个页面需要:首页会以最低优先级Lowest来提前加载
加入prefetch:
需要的页面,从prefetch cache中取
webpack也是支持这两个属性的:webpackPrefetch 和 webpackPreload
#3、懒加载
#图片
机械图片
渐进式图片(类似高斯模糊) 需要UI小姐姐出稿的时候指定这种格式
响应式图片
原生模式:
<img src="./img/index.jpg" sizes="100vw" srcset="./img/dog.jpg 800w, ./img/index.jpg 1200w"/>
#路由懒加载
通过函数 + import实现
const Page404 = () => import(/* webpackChunkName: "error" */'@views/errorPage/404');
十、ssr && react-snap
服务端渲染SSR,vue使用nuxt.js,react使用next.js
react-snap可以借助Puppeteer实现先渲染单页,然后保留DOM,然后发送到客户端
十一、体验优化
#白屏loading loading.html
需要自取哦,还有种方式,使用webpack插件HtmlWebpackPlugin将loading资源插入到页面中
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Loading</title><style>body {margin: 0;}#loadding {position: fixed;top: 0;bottom: 0;display: flex;width: 100%;align-items: center;justify-content: center;}#loadding > span {display: inline-block;width: 8px;height: 100%;margin-right: 5px;border-radius: 4px;-webkit-animation: load 1.04s ease infinite;animation: load 1.04s ease infinite;}@keyframes load {0%,100% {height: 40px;background: #98beff;}50% {height: 60px;margin-top: -20px;background: #3e7fee;}}</style></head><body><div id="loadding"><span></span><span style="animation-delay: 0.13s"></span><span style="animation-delay: 0.26s"></span><span style="animation-delay: 0.39s"></span><span style="animation-delay: 0.52s"></span></div></body><script>window.addEventListener("DOMContentLoaded", () => {const $loadding = document.getElementById("loadding");if (!$loadding) {return;}$loadding.style.display = "none";$loadding.parentNode.removeChild($loadding);});</script>
</html>
原文链接:
https://alexwjj.github.io/views/fe/others/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96.html#%E4%BA%8C%E3%80%81web-api
前端学习笔记????
最近花了点时间把笔记整理到语雀上了,方便同学们阅读:
公众号回复笔记或者简历
最后
1.看到这里了就点个在看支持下吧,你的「点赞,在看」
是我创作的动力。
2.关注公众号前端壹栈,回复「1」加入前端交流群
!「在这里有好多前端开发者,会讨论前端知识,互相学习」!
3.也可添加公众号【前端壹栈】
,一起成长
拯救你的年底 KPI:前端性能优化相关推荐
- (译)2019年前端性能优化清单 — 上篇
(译)2019年前端性能优化清单 - 上篇 (译)2019年前端性能优化清单 - 中篇 (译)2019年前端性能优化清单 - 下篇 写在译前:首先介绍一下我自己,一个跨行业的.完全非科班生的文科单身狗 ...
- 2019年前端性能优化清单
由于全文篇幅太长,无法将所有内容一次性发布完,所以计划分成上.中.下三个篇章.上篇包括( 计划和度量.制定现实的目标 和 定义环境 ),中篇包括( 资源优化.构建优化 和 交付优化 ),下篇包括( H ...
- 深度讲解:web前端性能优化
一.课程简介: 1.课程大纲 涉及到的分类 网络层面 构建层面 浏览器渲染层面 服务端层面 涉及到的功能点 资源的合并与压缩 图片编解码原理和类型选择 浏览器渲染机制 懒加载预加载 浏览器存储 缓存机 ...
- 大型网站技术架构(3):WEB 前端性能优化
上次说到了性能优化策略,根据网站的分层架构,可以大致的分为 web 前端性能优化,应用服务器性能优化,存储服务器性能优化三大类 这次来说一下 web 前端性能优化,一般来说,web 前端就是应用服务器 ...
- 前端性能优化——从 10 多秒到 1.05 秒
https://lishaoy.net 关于 性能优化 是个大的面,这篇文章主要涉及到 前端 的几个点,如 前端性能优化 的流程.常见技术手段.工具等. 提及 前端性能优化 ,大家应该都会想到 雅虎军 ...
- 移动H5前端性能优化指南[转]
移动H5前端性能优化指南 米随随2015.01.23 移动H5前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用 2. 在Mobile侧我们提出三秒种渲染完成首屏指标 3. 基于第二点 ...
- WEB前端性能优化小结
1. 请减少HTTP请求 基本原理: 在浏览器(客户端)和服务器发生通信时,就已经消耗了大量的时间,尤其是在网络情况比较糟糕的时候,这个问题尤其的突出. 一个正常HTTP请求的流程简述:如在浏览器中输 ...
- 前端性能优化最佳实践(转)
转载请注明: 转载自WEB前端开发(www.css119.com)-关注常见的WEB前端开发问题.最新的WEB前端开发技术(webApp开发.移动网站开发).最好的WEB前端开发工具和最全的WEB前端 ...
- 前端性能优化:使用媒体查询加载指定大小的背景图片
日期:2013-7-8 来源:GBin1.com 直到CSS @supports被广泛支持,CSS媒体查询的使用接近于CSS中写逻辑控制.我们经常用CSS媒体查询来根据设备调整CSS属性(通常根据屏 ...
- 如何给网站瘦身?图文并茂的前端性能优化指南
提高网站的速度对网站的成功有巨大的影响,因为网站的加载速度直接影响到用户体验和搜索引擎排名.Browser Diet 是一个非常好的指南,列出了前端性能优化的各种技巧和工具. 您可能感兴趣的相关文章 ...
最新文章
- Linux shell类型
- JZOJ 100026. 【NOIP2017提高A组模拟7.7】图
- 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。
- 基于keras中IMDB的文本分类 demo
- 【转载】用廉价的315M遥控模块实现数据传输
- 【送给Git初学者】
- ACL 2010-2020研究趋势总结
- java 数据结构 迷宫_JAVA数据结构与算法之递归(一)~ 迷宫问题
- 语言把数据写入csv文件_把JSON/CSV文件打造成MySQL数据库
- 修改Launcher2欢迎页面字符重叠
- 辨异 —— 有两人生日在同一天、只有两人生日在同一天
- linux长ping然后保存,Linux下长时间ping网络加时间戳并记录到文本
- 中标麒麟系统u盘安装_中标麒麟u盘安装系统教程
- 线面图标设计样式解析
- 数据中心IDC产业研究报告:碳中和背景下,IDC产业链的破局之路
- 我想吃掉你的胰脏--影片--观后感
- [转载]2016美国数学建模MCM F题(政策)翻译:难民移入政策建模
- 日本海淘转运运输方式对比及如何选择转运渠道
- 通过网格拆分高德地图
- 《观察与思考》:相信中国,寻找下一个比尔·盖茨
热门文章
- 【dp专题】在经历了时空扭曲后的总结
- 了解聚类是什么。聚类方法:k-means、核聚类、层次聚类、谱聚类
- python中表示嵌套语句快_Python编程(8)——if语句的嵌套,语言,程序设计,8if
- IP访问控制列表配置
- python ssh实时交互_python SSH客户端的交互式和非交互方式
- 如何解决医美行业获客难得问题,我是一名医美行业的营销人员
- 深度学习在超分辨率重建上的应用SRCNN,FSRCNN,VDSR,DRCN,SRGAN
- 心算(手算)开平方,比较有用
- C语言 goto语句
- Python基础的学习和简单爬虫的编写