性能优化篇

首屏性能优化

方法一:减少http请求
在这里插入图片描述
从图可知:发起了20次请求,这只是刚刚构建的项目。如果是真正的项目会达上百此。
这显然是不友好的.减少首屏加载请求次数

1、使用SplitChunks分离代码并实现相同模块共享,在需要时按需加载,从而减少请求次数
2、vue-router使用懒加载,plugin-syntax-dinamic-import
3、尽量避免组件库,UI库全局注入,最好是按需引用
4、组件懒加载

1、「使用SplitChunks分离代码并实现相同模块共享,从而减少请求次数」
安装BundleAnalyzerPlugin插件生成依赖包可视化分析图谱,帮助开发者分析项目结构

1)、npm install --save-dev webpack-bundle-analyzer查看的依赖

2)、vue.config.js中进行BundleAnalyzerPlugin插件配置


/** 开发环境 */
const DEV = process.env.NODE_ENV !== 'production';

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
 publicPath : './'  // 若要自动生成可视化分析页面,请将publicPath设置为相对路径
 configureWebpack: config => {
 
  /* **********************************************
   *
   * @description webpack 依赖包可视化分析
   * 仅在性能分析的时候启用
   * @Author: mingyong.g
   * @Date: 2020-09-02 21:24:31
   * 
   ***********************************************/
  //if(DEV){
   config.plugins.push(new BundleAnalyzerPlugin())
  //}
 }
}

3)运行npm run build --report 生成分析页面(npm run build --report
在这里插入图片描述

  1. 配置SplitChunks对注意模块进行分离
chainWebpack: config =>{
 if (!DEV) {
      config.optimization.splitChunks({
        cacheGroups: {
          common: {
            name: 'chunk-common', // 打包后的文件名
            chunks: 'all', // 
            minChunks: 2,
            maxInitialRequests: 5,
            minSize: 0,
            priority: 1,
            reuseExistingChunk: true
          },
          vendors: {
            name: 'chunk-vendors',
            test: /[\\/]node_modules[\\/]/,
            chunks: 'all',
            priority: 2,
            reuseExistingChunk: true,
            enforce: true
          },
          ElementUI: {
            name: 'chunk-element-ui',
            test: /[\\/]node_modules[\\/]element-ui[\\/]/,
            chunks: 'all',
            priority: 3,
            reuseExistingChunk: true,
            enforce: true
     },
     xlsx: {
      name:"chunk-xlsx",
      test: /[\\/]node_modules[\\/]xlsx[\\/]/,
      chunks: 'all',
            priority: 4,
            reuseExistingChunk: true,
            enforce: true
     }
    }
   })
  }
 },

在这里插入图片描述
方法二:压缩文件体积
压缩文件体积操作简单粗暴,效果却非常明显。常见的压缩文件体积的方法如下:

压缩图片体积,设置合适的图片尺寸
多图页面采用雪碧图(尤其是小图片)
开启GZIP压缩
关闭源码视图,清除console.log 日志

上述方案可根据具体情况考虑,比如我手下的项目主要是Vue+Element UI搭建的后台管理系统,并未涉及图片,因此只需采取方案3和方案4即可。

「Vue项目前端配置GZIP」
1、安装CompressionPlugin
npm i compression-webpack-plugin -D ,如果下载不了,降低版本
2、在vue.config.js中进行配置

 《vue cli3 将webpack配置和vue配置都集中在vue.config.js中管理,这一点需要注意和vue cli2 的区别.
 如果没有 vue.config.js文件可自行在项目「根目录下创建」》
 
const CompressionPlugin = require('compression-webpack-plugin');
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i;

/** 开发环境 */
const DEV = process.env.NODE_ENV !== 'production';


module.exports = {
 /* vue.config.js支持webpack-chain写法 */
 chainWebpack: config =>{
  /* *******************************************
   *  
   * 开启GZIP压缩
   * 压缩前:4.4MB
   * 压缩后:1.7MB
   * @Author: mingyong.g
   * @Date: 2020-09-02 19:55:13
   * 
   ********************************************/
   if(!DEV){
    config.plugin('compressionPlugin')
    .use( new CompressionPlugin({
     filename: "[path].gz[query]",
    algorithm:"gzip",
     test:productionGzipExtensions,  //所有匹配此{RegExp}的资产都会被处理
     threshold:512,   // 只处理大于此大小的资产。以字节为单位
     minRatio:0.8,    //只有压缩好这个比率的资产才能被处理
    deleteOriginalAssets:false //是否删除原资源
    }))
   }
}

在这里插入图片描述
方法三、提高打包速度

1、热更新
2、开启babel缓存
3、多进程打包
4、配置各种loader的时候限制或者排除一些文件

1、 速度分析:使用 speed-measure-webpack-plugin。可以看到每个 loader 和 插件的执行耗时。

安装依赖: npm i speed-measure-webpack-plugin -D

webpack.config.js

const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin')

 configureWebpack: {
 	// configureWebpack:config=>// configureWebpack使用箭头函数时用
    // if (DEV) {
    //   config.plugins.push(new BundleAnalyzerPlugin())
    // }
    plugins:[
      new BundleAnalyzerPlugin(),
      new SpeedMeasurePlugin()// 在这配置SpeedMeasureWebpackPlugin 
    ],
  },

下载配置之后SpeedMeasureWebpackPlugin ,重新npm run serve
在这里插入图片描述
2、开启babel缓存
在vue.config.js文件

module.exports = {
  chainWebpack: config => {
	 config.module.
	  	rule('babelLoader')
	    .test(/\.js$/)
	    .use('babel-loader?cacheDirectory=true')
	    .loader('babel-loader')
	    .end()
	    .include.add('/src')
	    .end()
	    .exclude.add('/node_modules/')
	}
}

在这里插入图片描述
3、使用hard-source-webpack-plugin 为模块提供中间缓存步骤

1) npm install --sasve hard-source-webpack-plugin
2)
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); 
module.exports = { 
plugins:[
  	 new HardSourceWebpackPlugin()   
] }

4、happypack多线程打包

1)npm install happypack --save-dev

2)在vue.config.js 配置
  config.module
 .rule('happypack')
                .test(/\.js$/)
                .include.add(resolve('src'))
                .end()
                .exclude.add('/node_modules/')
                .end()
                .use('happypackloader')
                .loader('happypack/loader?id=happyBabel')
                .end()
 3)配合共享线程池加快构建速度
  
      config.plugin('uglify').use(require('happypack'), [
        {
            id: 'happyBabel',
            loaders: [
                {
                    loader: 'babel-loader?cacheDirectory=true'
                }
            ],
            // 共享进程池
            threadPool: happyThreadPool,
            // HappyPack 输出日志
            verbose: true
        },
        
    ])

筛选策略:
为什么压缩不建议对图片开启gzip
答:对于js\css\html这些文件来说,当你开启gzip压缩之后,往往都会压缩到原有体积的1/3,但是对于图片开启gzip压缩之后,体积可能没有什么变化,因为主流格式的图片,比如jpg\png\gif,其实已经进行了压缩算法了,如果再用gzip压缩一回,体积不会有什么庇变化,甚至体积会变得更大。最终加大了网站的响应时间,浪费的cpu资源

图片优化:
1)图片懒加载
2)图标转变为雪碧图

路由懒加载:@babel/plugin-syntax-dynamic-import
1) ES6 动态引入路由组件
2) webpack路由懒加载插件
3) chunkName

组件懒加载:

tree shaking

白屏优化
1)骨架屏
2) 我们只需要再这里添加loading图或者骨架屏
3) 模仿defer, 比如如果有很多节点,可以先将屏幕上需要显示的节点显示,其他的延迟,

首屏优化
加快构建速度

长列表虚拟滚动
如何判断一个元素在不在可视区域内

在有滚动条的情况下,判断元素是否在可视区域内可以使用 JavaScript 来实现。以下是一种常见的方法:

获取窗口或容器的滚动位置: 首先,需要获取窗口或容器的滚动位置,以确定滚动条滚动了多少距离。

const scrollY = window.scrollY || window.pageYOffset; // 获取垂直滚动位置
const scrollX = window.scrollX || window.pageXOffset; // 获取水平滚动位置


获取元素的位置和尺寸: 
使用 JavaScript 获取要判断的元素的位置和尺寸,包括元素的上边缘和下边缘的位置。

const element = document.getElementById('your-element-id');
const elementRect = element.getBoundingClientRect(); // 获取元素的位置和尺寸
const elementTop = elementRect.top + scrollY; // 元素顶部相对于窗口的位置
const elementBottom = elementRect.bottom + scrollY; // 元素底部相对于窗口的位置


判断元素是否在可视区域: 使用滚动位置和元素的位置信息,判断元素是否在可视区域内。
 // 窗口高度
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
 // 窗口宽度
const windowWidth = window.innerWidth || document.documentElement.clientWidth;

const isElementInViewport = (elementTop >= 0 && elementBottom <= windowHeight) &&
  (elementRect.left >= 0 && elementRect.right <= windowWidth);

if (isElementInViewport) {
  // 元素在可视区域内
} else {
  // 元素不在可视区域内
}

白屏优化或者叫前端优化之如何做到渲染几十万条数据不卡帧,
使用createDocumentFragment和requestAnimationFrame,渲染大量数据页面不卡顿

1、实现思路:

渲染大量数据时,合理使用 createDocumentFragment 和 requestAnimationFrame,将操作且分为一小段一小段去执行,从而实现页面不卡顿。

2、createDocumentFragment()

是用来创建一个虚拟的节点对象(用来创建文档碎片节点),该节点是一个虚拟节点,不属于文档树。在将 DocumentFragment 节点插入文档树时,插入的并不是 DocumentFragment 节点本身,而是插入他的子节点(后代节点)。 当需要添加向页面添加很多DOM元素时(如添加很多个 li 标签),如果一个个createElement出来,然后再一个个appendChild上去,会频繁的操作DOM,很影响性能。因此可以可以使用 DocumentFragment 节点,先把 li 标签添加到 DocumentFragment,然后由 DocumentFragment 统一添加到页面上,会大大减少DOM操作,性能明显提升。(因为插入DocumentFragment节点的时候是插入他的后代节点,所以最后的实现效果是一样的,但性能有很大的提升。)

3、requestAnimationFrame() // 传入一个 回调函数/动画

该方法功能类似于 setInterval,但 requestAnimationFrame 在性能方面会更好一些。它不需要设置时间间隔,它的时间间隔由系统定义(一般为16.67ms),保证最佳的绘制效率。 requestAnimationFrame() 浏览器没刷新一次,回调代码执行一次,不会造成丢帧或卡顿的现象,且当页面最小化或者隐藏时,requestAnimationFrame 会暂停渲染,当页面重新激活时,会从上次暂停的地方继续开始渲染,故性能方面会更好。

function renderOfNoStuck(total,parentNode,once){
// total:必选,需要渲染的数据总量(可根据需求自定义)
// parentNode:必选,需要将数据渲染到哪个节点下
// once:可选,分段渲染时一小段渲染的数据量,默认为 20

	if (!parentNode || parentNode.nodeType !== 1) {
	    // nodeType === 1 为元素节点 (2为属性节点,3为文本节点)
	    throw new TypeError('请传入正确的参数');
	}
	setTimeout(() => {
	    // 把大量数据切成一小段一小段进行渲染
	    const once = once || 20; // 一小段渲染的数据量(可根据需求自定义)
	    const loopCount = Math.ceil(total / once);  // 插入数据需要的次数
	    let countOfRender = 0; // 已渲染的数据量
	    // 添加数据的方法
	    function add() {
	        const fragment = document.createDocumentFragment();	// 创建一个 DocumentFragment节点
	        for (let i = 0; i < once; i++) {
	            const li = document.createElement('li');
	            li.innerText = Math.floor(Math.random() * total); // 给标签添加内容 (可根据需求自定义)
	            fragment.appendChild(li); // 把数据先添加到 DocumentFragment 节点上
	        }
	        parentNode.appendChild(fragment); // 然后由 DocumentFragment 节点统一渲染到页面
	        countOfRender += 1;
	        loop();
	    }
	    function loop() {
	        if (countOfRender < loopCount) {
	            window.requestAnimationFrame(add); // requestAnimationFrame 传入回调函数add,渲染数据
	        }
	    }
	    loop();
	}, 0)
}
// let parentNode = document.querySelector('ul');
// renderOfNoStuck(100000, parentNode)
// renderOfNoStuck(20, parentNode, 1) // 设置成 1 时有一个比较好看的效果

seo优化

SEO(Search Engine Optimization):汉译为搜索引擎优化。利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,获得品牌收益。
seo优化策略有三种:1、预渲染,2、SSR服务端渲染,3、同构渲染
1、预渲染:
定义:预渲染(Prerendering)是指在网页加载前,事先生成完整的静态HTML内容,然后将其缓存或保存下来,当用户请求该页面时,直接返回静态HTML,而无需再进行客户端渲染。

1、安装插件:prerender-spa-plugin,然后在
2、vue.config.js引入,配置,配置的时候打包有几个路由,就配置对应的几个路由,一般是首页、关于、联系我们这些。
3、然后要动态地去改变title描述关键字,这需要下载一个 vue-meta-info依赖。然后在相应的组件中写引入一个包含title、meta等关键字的metaInfo对象

优点:
1)适合项目某几个页面做seo,提升排名吸引流量
2)用户访问时直接返回静态页面,减少了客户端渲染时间,提供更快的初始加载速度。
缺点:
1)提前生成和存储的静态 HTML 文件,如果有很多详情页就不适合了,那会占用更多的服务器存储空间。
2)预渲染对于动态内容或需要频繁更新的页面可能不适用,动态去改变title、描述、关键字是无效的。

2、ssr服务端渲染
指在服务器端生成并返回完整的渲染好的 HTML 页面,而不是将页面的渲染任务交给客户端的浏览器来完成。

服务端渲染:nuxt.js
1、nuxt上线流程
1)npm run build
2)nuxt.config
.nuxt
package.json
static 放到服务器中
3)npm run start

预渲染和SSR服务端渲染的不同
预渲染(Prerendering)是在构建时生成静态 HTML 页面,这些页面在每个路由的请求时直接提供给客户端。
与服务端渲染相比,预渲染的主要区别在于它不是在每个请求时动态生成 HTML 页面,而是在构建过程中生成预先渲染好的静态页面。

3、同构渲染

1)所谓同构,简单的说就是一份代码,即能进行服务端渲染(server-side rendering => ssr),也能通过客户端来渲染(client-side rendering => csr)。
2)而同构渲染,则是一种渲染方案。它是指,服务端先通过 SSR,生成 html 以及初始化数据,客户端拿到代码和初始化数据后,通过对 html 的 dom 进行 patch 和事件绑定,即客户端激活(client-side hydration => csh)
3)实现同构:基本思路,使用 webpack 同时打包客户端和服务端应用,其中服务端的包会被引入到服务端用来渲染 HTML,同时客户端的包会被送到浏览器用于 激活静态标记.
与之对应的两个入口文件就是:entry-client.js 和 entry-server.js

前端性能优化

答:前端性能优化范围比较大,我做过一些总结。一般项目做性能优化,都会借助几个工具去观测,比如,控制台的performance、lightHourse、查看打包体积情况的工具webpack-bundle-analyzer,看构建速度的工具 speed-measure-webpack-plugin。典型模块的性能优化有以下几个:图像优化、加载优化、构建优化、渲染优化、数据存储、http缓存,seo优化
1、图像优化:

小图标可以做成雪碧图、使用webp格式,svg格式图标,图片的压缩等等这样的内容

2、加载优化

1)、使用SplitChunks分离代码并实现相同模块共享,在需要时按需加载,从而减少请求次数
2)、路由懒加载
3)、尽量避免组件库,UI库全局注入,最好是按需引用
4)、组件懒加载

3、 构建优化(webpack)

1)、加快构建速度(热更新)
2)、开启babel缓存、cache缓存
3)、多进程打包
4、配置各种loader的时候限制或者排除一些文件
5)、开启GZIP压缩
6)、关闭生产环境下的SourceMap映射文件,清除console.log 日志

4、 渲染优化
5、数据存储

利用浏览器的web存储机制和vuex

6)、http缓存

强缓存和协商缓存

7)、seo优化

1)预渲染:基本上都是启动无头浏览器,加载页面路由并将结果保存为静态HTML文件,然后返回给客户端
2)SSR服务端渲染:
3)同构渲染

1)工具分析
2)模块
3)各模块下的具体措施

补充:当我们在做一个项目的,随着时间推移,从零到1也是一个不断优化的一个过程。
优化不一定是代码优化,像用户体验,这个就和产品有关系。优化包含代码优化
在优化的时候,有一些共性的问题,,也有一些比较特殊的问题。共性问题有哪些呢?举一些例子:在做项目的时候,懒加载、代码压缩、提高构建速度,这些几乎是每一个项目都要做的。但是有一些特殊的优化,不是所有项目都有的业务,比如视频、音频这些。对视频、对上传这些做一些优化。使用了哪些工具。
一般项目做性能优化,都会借助几个工具去观测,比如,控制台的performance、查看打包体积情况的工具webpack-bundle-analyzer,看构建速度的工具 speed-measure-webpack-plugin。
然后具体的优化是分为几类,加载优化、图片优化css优化、js优化、渲染优化、首屏优化、打包优化、还有一些webpack优化、vue优化。共性的尽量说全:比如加载优化,压缩打包合并、代码分割、大模块异步加载、小模块合并等等这些内容。图片优化,如果有小图标可以做成雪碧图、图片的懒加载、使用webp格式,svg格式图标,图片的压缩等等这样的内容。css优化、js优化、渲染优化,避免重排重绘这些内容、首屏的优化、白屏的优化、还有打包分模块、分包优化

前端性能指标FP、FCP、FMP

前端性能指标FP
1、概念
中文叫首屏绘制, 也叫白屏时间。first print。指浏览器从用户输入网址到浏览器刚开始显示内容的一个时间。
2、如何计算FP
performance对象,在body onload的时候触发,可以看到fp用了多少时间,fp正常值是0~2秒以内
3、FP原因分析优化策略

1)cdn解析时间过长, 出现概率比较低。如果出现了可以用nslook去排查
2) tcp的三次握手时间过长,使用云上服务器的出现的概率也比较低,如果在海外的话,可能就比较长了。排查方式:使用vpn ping 一下自身的服务器的ip或者端口,如果过高,三次握手就会过长。
3)html请求时间过长。这个可能的因素是html太大了,首次下载就很慢。没有做一定加速、缓存之后的情况。这个可以从浏览器去查看文件大小,下载时长去排查这个问题
4)ttfb时间过长,这个一般可能是服务器性能问题
5)解析header的时间过过长。这个原因的话就多种多样了,因为header中包含的元素有css样式,js可执行脚本。如果在执行的过程中,加载了较多css样式,而且样式的文件很大,那么可能直接就导致执行时间过长。同样js也存在同样的问题,因为js在此期间需要去执行的。如果js下载时间过长或者执行时间过长,都可能是导致白屏时间的核心问题。
解析header时间过长是白屏时间过长的重要的排查的点

4、performance对象,在body onload的时候触发,可以看到fp用了多少时间,fp正常值是0~2秒以内,fcp是2秒,而fcp是大于等于fp的

5、注意:在HTTP2.0一下,会有一个阻塞的问题:比如果我们有10个一样的css文件都来自同一个域名,浏览器呢会有一个并发限制,比如说chrome,它同时只对同一个域名并发5个请求,因此,过多的css和js会影响请求市场,因为需要排队,这也是我们为什么要将css\js打包合并的原因。为什么从多个文件,多个js文件或css文件压缩成一个或者几个,这也减少了http请求。

6、前提内容:浏览器从用户输入网址到浏览器刚开始的过程:

1)、dns查询,因为要查询一个域名二dns
2)、拿到域名的ip和端口以后要建立TCP连接,要做三次握手
3)、接下来要去发送首个http的请求,
4)、然后服务端响应返回一个html的资源
5)、你还要获取解析文档,解析他的一个header, FP的话是解析到Header就ok了

前端性能指标fcp

1、概念

首次内容绘制,first content paint。绘制背景

、像素的时候就叫fp,接下来解析hhtml绘制dom结构的时候叫fcp

2、如何计算值

打开控制台fp:第一个节点

console.log(performance.getEntriesByType(‘paint’)[0])

fcp:第二个节点

console.log(performance.getEntriesByType(‘paint’)[1])

唯一的区别就是第一个节点是背景绘制,第二个节点是dom绘制

3、异常如何处理

与fp一样

FMP 第一次有意义的绘制,请求数据回来之后的渲染数据
****预渲染相当于将FPM提升到了FP阶段

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值