为什么你的页面速度慢/操作卡/体积大?【前端性能优化思路】 | 您所在的位置:网站首页 › 下载视频慢是什么原因呢怎么解决 › 为什么你的页面速度慢/操作卡/体积大?【前端性能优化思路】 |
开发时很经常会遇到一种情况:刚接手了一个现有的已发布至生产项目,就会被甩下三个问题 为什么打开这么慢? 为什么这么卡? 为什么打出来的包这么大? 1.为什么打开这么慢?这里的慢一般指的是,页面的白屏(FP)到首屏完整(FCP)加载加起来的时长。 问题分析先问清楚问题的复现过程,偶现还是必现,偶现的话有没有什么具体的时间段或者网络是否正常。有无特定的复现机型、系统、浏览器。了解更详细的信息有助于我们排查问题 若没有解决的话就得从前端开始入手,导致慢的原因有很多种可能,用chrome打开页面,按f12,转到network,勾上Disable cache network相关功能说明及使用技巧可以参照这篇文章。Chrome教程(一)NetWork面板分析网络请求 首先我们需要知道的是,浏览器加载的触发流程大致是根据以下步骤进行的: 解析 HTML 结构,并且构建成一棵DOM树。 加载外部脚本和样式表文件 解析并执行脚本代码 // 部分脚本会阻塞页面的加载 DOM树构建完之后,浏览器把DOM树中的一些不可视元素去掉,然后与CSSOM合成一棵render tree。 加载图片等外部文件 页面进行渲染,加载完毕 // load事件
首先我们先使用chrome的performance对页面的性能进行解析,具体使用教程可以参照这篇文章 得到上面的图片之后,我们就可以针对占用时间较长的模块进行优化。底部的饼图有总的耗时时间,一般都是scripting和rendering占用的时间较多。 Scripting:Javascript执行 Rendering:样式计算和布局,即重排 Painting:重绘 对应的详细事件 问题分析首先我们需要知道,一般的显示器是刷新率是 60 HZ,一个流畅的网页动画的要求就是 1 秒 60 帧,即一秒重新渲染页面 60 次,一次渲染出来的页面叫一帧,动画的本质就是帧的切换。在一次事件循环里,一个宏任务被执行后,js 修改了样式,浏览器也不一定会重新渲染,浏览器可能等到下一次事件循环再一起渲染,而中间没有渲染的那一次,就不会再被渲染出来了,这就叫 “丢帧”。 页面重新渲染间隔大于 16.67 毫秒,动画就会产生卡顿; 优化思路减少会引起回流和重绘的操作 尽量使用CSS3动画,CSS3动画在大部分浏览器都开启了硬件加速,比如:在css属性上加上transform:translateZ(0)开启硬件加速 减少js访问dom的次数,部分如window对象的resize,scroll事件,还有document.mousemove等事件,频繁执行dom操作,资源加载等重行为,导致UI停顿甚至浏览器奔溃。建议对函数里面需要执行的函数进行节流操作 如果是使用了setTimeout 或 setInterval 函数来执行动画导致页面卡顿了的话,可能是丢帧的原因导致的,可以看看window.requestAnimationFrame() 方法,将需要用js改变样式代码统一放到下一次重新渲染时执行。 优化可能会引起阻塞的js代码,看看有没有什么死循环或者时间复杂度较高的函数,优化掉 3.为什么打出来的包这么大 问题分析webpack-bundle-analyzer是webpack的一款可视化工具插件 它可以直观分析打包出的文件包含哪些,大小占比如何,模块包含关系,依赖项,文件是否重复,压缩后大小如何,针对这些,我们可以进行文件分割等操作。 vue-cli创建的项目里,在package.json里的script里加上--report,然后运行,旧的版本是会直接让你打开一个地址,新的版本会在打包后的目录里生成一个report.html,打开即可。 "scripts": { ... "build": "vue-cli-service build --report", ... }其他使用webpack创建的目录可以用 npm install --save-dev webpack-bundle-analyzer然后在webpack的plugins配置的地方引入即可 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { plugins: [ new BundleAnalyzerPlugin() ] } 优化思路关于webpack对包大小的优化,在webpack4的版本几乎都合并到optimization选项里了,可以逐个翻阅 逐个检查webpack的插件,去除可能会导致包体积增加的没必要的插件,例如部分只需用于本地调试用的插件HotModuleReplacementPlugin等 使用webpack的压缩代码的插件uglifyjs-webpack-plugin,或者使用在线压缩代码的网页对代码进行压缩。 //webpack.config.js const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); optimization: { minimizer: [new UglifyJsPlugin()], },webpack4以上的话不用以上的写法,直接使用optimization.minimize,详情可以翻阅文档。 TreeShaking可以在打包的时候帮我们移除javascript上下文中的未引用代码。TreeShaking在webpack2已经支持了。但是旧的项目如果用的是webpack3或之前的版本,考虑升级至webpack4/5,webpack4以上的版本对TreeShaking的检测能力进行进一步的优化。 webpack4之前的SplitChunksPlugin以及webpack4之后的optimization.splitChunks,可以抽取页面的公用模块,避免不同页面之间的重复依赖。下面是optimization.splitChunks的示例代码。 module.exports = { optimization: { splitChunks: { chunks: "async",// all async initial minSize: 30000, maxSize: 0, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: "~", name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } }, }引用例如lodash、moment等常用工具库的时候,优先考虑按需引入,或将需要使用到的部分代码,直接拷贝至项目常用的工具函数文件中,自己维护一套常用的工具库,减少包的体积。 假如要引用现成的内存较大的库,比如echarts、jquery等,优先考虑CDN引入从而减少包的体积。建议是公司自己维护一套CDN服务器,以免外网服务的CDN突然下线导致服务崩溃。 给CDN地址加上dns-prefetch,可以对DNS进行预解析。尽量把预解析的代码写到页面的最开始的部分,能尽快加载 //href只需要填你需要请求的域名//+你请求的域名,如下例使用了CDN之后,webpack的项目还可以搭配external,设置import引入的包的名字,之后你就可以像使用npm安装的包一样直接import相对应的名字就可以使用。而且webpack打包时会不从node_modules把external中的包打包进去,从而减少打包的体积 //index.html,引入CDN服务器的Jquery //webpack.config.js,然后再webpack中设置externals module.exports = { //... externals: { jquery: 'jQuery', }, }; //引入的时候就和npm安装的包一样,用import引入即可 import $ from 'jquery'; $('.my-element').animate(/* ... */); 部分大一点的库还会将部分代码进行拆分,可以进行模块化引入。如echarts、loadsh等 import { debounce } from 'lodash' import { throttle } from 'lodash' // 改成如下写法,找到相对应的库的地址即可 import debounce from 'lodash/debounce' import throttle from 'lodash/throttle'如果项目较大的话考虑使用微前端的方式对项目进行拆分,可以参考qiankun 以上仅为本人整理的常见的优化思路,欢迎大家补充,实在不行就花钱买更好的服务器配置!重构整个项目!包治百病!看完的话麻烦点个赞啦谢谢 |
CopyRight 2018-2019 实验室设备网 版权所有 |