为什么你的页面速度慢/操作卡/体积大?【前端性能优化思路】 您所在的位置:网站首页 下载视频慢是什么原因呢怎么解决 为什么你的页面速度慢/操作卡/体积大?【前端性能优化思路】

为什么你的页面速度慢/操作卡/体积大?【前端性能优化思路】

#为什么你的页面速度慢/操作卡/体积大?【前端性能优化思路】| 来源: 网络整理| 查看: 265

开发时很经常会遇到一种情况:刚接手了一个现有的已发布至生产项目,就会被甩下三个问题

为什么打开这么慢? 为什么这么卡? 为什么打出来的包这么大? 1.为什么打开这么慢?

这里的慢一般指的是,页面的白屏(FP)到首屏完整(FCP)加载加起来的时长。

问题分析

先问清楚问题的复现过程,偶现还是必现,偶现的话有没有什么具体的时间段或者网络是否正常。有无特定的复现机型、系统、浏览器。了解更详细的信息有助于我们排查问题

若没有解决的话就得从前端开始入手,导致慢的原因有很多种可能,用chrome打开页面,按f12,转到network,勾上Disable cache

image.png

network相关功能说明及使用技巧可以参照这篇文章。Chrome教程(一)NetWork面板分析网络请求

首先我们需要知道的是,浏览器加载的触发流程大致是根据以下步骤进行的:

解析 HTML 结构,并且构建成一棵DOM树。 加载外部脚本和样式表文件 解析并执行脚本代码 // 部分脚本会阻塞页面的加载 DOM树构建完之后,浏览器把DOM树中的一些不可视元素去掉,然后与CSSOM合成一棵render tree。 加载图片等外部文件 页面进行渲染,加载完毕 // load事件

image.png 接着我们就可以看是什么内容的time占用时长最多,根据不同文件、接口的加载时间进行相对应的优化。

优化思路 1.网络问题 压缩打包体积,减少请求的数量,降低服务器压力。【文章的第三大问会展开讲】 开启gzip。在请求中的request headers 中加上accept-encoding:gzip,服务器收到此请求信息后,通过Gzip来对Response进行编码,可减少文件70%的体积 服务器开启页面缓存,如果符合设置条件的话,之后前端的请求会直接获取浏览器的缓存。缓存分为强缓存和协商缓存。加快了客户端加载网页的速度的同时,也减少了服务器的负担,大大提升了网站的性能 //max-age=31536000 等同于页面在31536000时间戳之内。 cache-control: max-age=31536000 //expires expires: Wed, 11 Sep 2019 16:12:18 GMT 把所有用到的图片、js文件等放在同一个域名的服务器,减少dns解析 给CDN地址加上dns-prefetch,可以对DNS进行预解析。尽量把预解析的代码写到页面的最开始的部分,能尽快加载 //href只需要填你需要请求的域名//+你请求的域名,如下例 给需要首屏不需要使用到的js或者css文件,使用link+prefetch/preload进行预加载。优化之后打开其他页面的速度。 // preload 是告诉浏览器页面必定需要的资源,浏览器一定会加载这些资源 prefetch 是告诉浏览器页面可能需要的资源,浏览器不一定会加载这些资源 在VUE SSR生成的页面中,首页的资源均使用preload,而路由对应的资源,则使用prefetch 2.js问题 将不需要的首屏加载的script,加上async或defer,减少js阻塞渲染进程的时间 如果 async="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行) 如果不使用 async 且 defer="defer":脚本将在页面完成解析时执行 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本 如果加载的文件不需要影响到首屏渲染的话,尽量放在body的底部,避免阻塞渲染进程,浏览器会在获取到部分DomTree、CssTree的时候合并RenderTree来进行页面渲染。 对于需要引入的文件或者是页面进行按需加载、懒加载等优化 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。 提取公用函数及逻辑,减少重复代码 3.httml+css问题 减少页面会触发回流重绘的操作,具体可以参照这篇文章《浏览器的回流与重绘》 尽量减少css选择器的层级,直接赋予id或者class进行样式的添加 尽量不要用js操作css,如果一定要用的话也记得,先把读取样式的操作放在前面执行,然后再将执行添加/修改样式的操作。在涉及到dom操作的时候尽量都现将js的逻辑先写完,然后再去一次性操作dom。 长列表可以采用虚拟列表进行实现,数据量过多的使用骨架屏、loading样式、分页也能优化用户体验 4.图片问题 JPG 有损压缩、体积小。PNG无损压缩、质量高。在不同的情况用不同的格式有利于优化图片加载速度。 在轮播大图、头像等一般使用JPG,图标、大logo的话一般使用PNG。 部分内存较小的图片可用在线转换网站,将图片转换成bse64格式再进行加载,能够减少http的请求次数。 将许多小的图合并至同一张图中,然后通过css进行加载,这种做法合并的图一般叫做雪碧图。可以使用在线网站css sprites tool,直接上传你需要的图标,他会帮你合并图片并且生成对应的css预览。 时间足够的话,部分图片也可以考虑用canvas/svg进行实现,优化性能。 图片懒加载。对还没到可视区域的图片进行隐藏,常用方法是将src设置为空,然后监听页面的滚动事件,滚动到一定距离的时候可以将图片src设置回原来的地址。 2.为什么这么卡

首先我们先使用chrome的performance对页面的性能进行解析,具体使用教程可以参照这篇文章

image.png

得到上面的图片之后,我们就可以针对占用时间较长的模块进行优化。底部的饼图有总的耗时时间,一般都是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.为什么打出来的包这么大 问题分析

93f72404-b338-11e6-92d4-9a365550a701.gif

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 实验室设备网 版权所有