0


部分性能优化

程序员面试之性能优化

“哈拉雷,今天分享的是性能优化之首页资源压缩与白屏时间缩短”

路由懒加载

SPA 项目,一个路由对应一个页面,如果不做处理,项目打包后,会把所有页面打包成一个文件,当用户打开首页时,会一次性加载所有的资源,造成首页加载很慢,降低用户体验

  • app.js与app.css体积在这里插入图片描述!a01eb92.png
// 通过webpackChunkName设置分割后代码块的名字constHome=()=>import(/* webpackChunkName: "home" */"@/views/home/index.vue");constMetricGroup=()=>import(/* webpackChunkName: "metricGroup" */"@/views/metricGroup/index.vue");const routes =[{path:"/",name:"home",component: Home
    },{path:"/metricGroup",name:"metricGroup",component: MetricGroup
    }]

重新打包后,首页资源拆分为 app.js 和 home.js,以及对应的 css 文件

  • app.js:244 KB、 home.js: 35KBapp.js:244 KB、 home.js: 35KB
  • app.css:67 KB、home.css: 15KB

在这里插入图片描述

通过路由懒加载,该项目的首页资源压缩约

52%

路由懒加载的原理

懒加载前提的实现:ES6的动态地加载模块——import()

调用 import() 之处,被作为分离的模块起点,意思是,被请求的模块和它引用的所有子模块,会分离到一个单独的 chunk 中
——摘自《webpack——模块方法》的import()小节

要实现懒加载,就得先将进行懒加载的子模块分离出来,打包成一个单独的文件

webpackChunkName 作用是 webpack 在打包的时候,对异步引入的库代码(lodash)进行代码分割时,设置代码块的名字。webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中

组件懒加载

话不多说,直接上效果

home 页面 和 about 页面,都引入了 dialogInfo 弹框组件,该弹框不是一进入页面就加载,而是需要用户手动触发后才展示出来

<template><div class="homeView"><p>home 页面</p><el-button @click="dialogVisible = !dialogVisible">打开弹框</el-button><dialogInfo v-if="dialogVisible"/></div></template><script>import dialogInfo from'@/components/dialogInfo';exportdefault{name:'homeView',components:{
    dialogInfo
  }}</script>

项目打包后,发现 home.js 和 about.js 均包括了该弹框组件的代码(在 dist 文件中搜索dialogInfo弹框组件)
在这里插入图片描述

当用户打开 home 页时,会一次性加载该页面所有的资源,我们期望的是用户触发按钮后,再加载该弹框组件的资源

这种场景下,就很适合用懒加载的方式引入

弹框组件懒加载:

<script>constdialogInfo=()=>import(/* webpackChunkName: "dialogInfo" */'@/components/dialogInfo');exportdefault{name:'homeView',components:{
    dialogInfo
  }}</script>

重新打包后,home.js 和 about.js 中没有了弹框组件的代码,该组件被独立打包成 dialogInfo.js,当用户点击按钮时,才会去加载 dialogInfo.js 和 dialogInfo.css
在这里插入图片描述
最终,使用组件路由懒后,该项目的首页资源进一步减少约

11%

组件懒加载的使用场景:

有时资源拆分的过细也不好,可能会造成浏览器 http 请求的增多

总结出三种适合组件懒加载的场景:

  1. 该页面的 JS 文件体积大,导致页面打开慢,可以通过组件懒加载进行资源拆分,利用浏览器并行下载资源,提升下载速度(比如首页)
  2. 该组件不是一进入页面就展示,需要一定条件下才触发(比如弹框组件)
  3. 该组件复用性高,很多页面都有引入,利用组件懒加载抽离出该组件,一方面可以很好利用缓存,同时也可以减少页面的 JS文件大小(比如表格组件、图形组件等)

合理使用 Tree shaking

Tree shaking 的作用:消除无用的 JS 代码,减少代码体积

exportfunctiontargetType(target){returnObject.prototype.toString.call(target).slice(8,-1).toLowerCase();}exportfunctiondeepClone(target){returnJSON.parse(JSON.stringify(target));}

项目中只使用了 targetType 方法,但未使用 deepClone 方法,项目打包后,deepClone 方法不会被打包到项目里

tree-shaking 原理:

依赖于ES6的模块特性,ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,这就是 tree-shaking 的基础

静态分析就是不需要执行代码,就可以从字面量上对代码进行分析。ES6之前的模块化,比如 CommonJS 是动态加载,只有执行后才知道引用的什么模块,就不能通过静态分析去做优化,正是基于这个基础上,才使得 tree-shaking 成为可能

Tree shaking 并不是万能的
并不是说所有无用的代码都可以被消除,还是上面的代码,换个写法 tree-shaking 就失效了

// util.jsexportdefault{targetType(target){returnObject.prototype.toString.call(target).slice(8,-1).toLowerCase();},deepClone(target){returnJSON.parse(JSON.stringify(target));}};// 引入并使用import util from'../util';
util.targetType(null)

同样的,项目中只使用了 targetType 方法,未使用 deepClone 方法,项目打包后,deepClone 方法还是被打包到项目里

在 dist 文件中搜索 deepClone 方法:
在这里插入图片描述
究其原因,export default 导出的是一个对象,无法通过静态分析判断出一个对象的哪些变量未被使用,所以 tree-shaking 只对使用 export 导出的变量生效

这也是函数式编程越来越火的原因,因为可以很好利用 tree-shaking 精简项目的体积,也是 vue3 全面拥抱了函数式编程的原因之一

原文链接


本文转载自: https://blog.csdn.net/qq_43803987/article/details/135558809
版权归原作者 木秃头的前端 所有, 如有侵权,请联系我们删除。

“部分性能优化”的评论:

还没有评论