简介
这是在公司对项目优化的一次记录,过程中并没有使用什么高大上的技术,因为造成问题的原因也并不复杂,大部分原因是对vue框架不够理解造成没有合理使用。
起因
某天早上领导估计看我闲来无事于是给了我个任务,项目有个模块是以前的同事写的,同事写前端的时间不长,目前功能已经完成了,但是打开页面的时候很慢,所以想让我去尝试优化一下。
发现问题
虽然这个模块不是我做的,而且这个项目我也还不熟悉,不然既然接到任务了就试试吧,想要对其进行优化,那么就得先了解该模块的具体情况,这样才能对症下药,拿出合理的方案。
页面是用于展示可视化报表,页面有七八个报表,还有一些按钮用于切换报表,除此之外没啥了,内容看起来并不复杂,不过打开页面到报表有响应大概就花了五六秒,报表完全展示需要差不多一分钟左右,为了防止这是偶然事件,我多试了好几遍,结果大差不差,这个速度可以说相当慢了。
考虑到其他页面都是正常的,唯独这个页面慢,因此先不考虑整个项目的性能问题,而是这个页面有问题,优先想到了是页面的渲染以及网络请求的问题。先打开页面调试台,看是不是DOM树太多节点了,导致渲染出现了问题。
果然发现了问题,页面用到了iframe,每个报表都是iframe嵌入了一个页面,再看了下网络请求,更是倒吸一口凉气,这个页面进来时发送了差不多4500个请求,难怪性能高这么差了。
下面是请求的图片:
虽说用到了iframe,但是也不至于会发送那么多请求啊,带着这个疑问去去看了下代码,发现代码确实有问题,代码大概是这样的,下面代码只是一个示例,是用来体现问题出现在了哪里,因此省略了一部分,不用纠结代码写得怎么样:
<template> <div> <el-radio-group v-model="radio" size="large"> <el-radio-button label="1" value="1" /> <el-radio-button label="2" value="2" /> </el-radio-group> <div v-for="list in dataList" :key="list.type" v-show="item.type === 'radio'"> <div v-for="item in list" :key="list.id"> <iframe :scr="item.url" /> </div> </div> </div> </template> <script> export default { data() { return { radio: '1', dataList: [ { type: '1', urlList: [ { url: "xxxxxxxxxxxxxxxxxxxxx", id: '1' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '2' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '3' }, ......... // 还有数据省略 ] }, { type: '2', urlList: [ { url: "xxxxxxxxxxxxxxxxxxxxx", id: '4' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '5' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '6' }, ........ // 还有数据省略 ] }, .......... // 还有数据省略 ] } } } </script>
上面示例的代码,问题就在使用了v-show来隐藏或展示需要想要的视图,v-show这个指令只是在DOM节点中加上display: none; 让节点隐藏不渲染,但是节点还是会挂载在DOM树中。
也正是因为这样,大概有五十多个iframe节点都挂在了DOM上,只是没有渲染出来,但是它们都发送了请求,因此刚刚进入页面的时候是请求了五十多个iframe页面的请求。
这导致了初始打开页面时会发送大量的请求,同时间大量的请求抢占了浏览器的资源,导致了页面响应慢。
解决问题
既然已经发现了主要问题是因为初始进入页面时请求了太多资源导致的,那么优先想到的就是按需加载的方案,既是只加载页面需要的数据,不加载多余的数据,代码大致如下。
<template> <div> <el-radio-group v-model="radio" size="large"> <el-radio-button label="1" value="1" /> <el-radio-button label="2" value="2" /> </el-radio-group> <div v-for="item in list" :key="item.id"> <iframe :scr="item.url" /> </div> </div> </template> <script> export default { data() { return { radio: '1', dataList: [...// 省略] } }, computed: { list:() => { const target = list.find(item => item.type === this.radio) return target.urlList } } } </script>
修改的并不多,只是使用了vue的计算属性computed,每次切换按钮,computed中的依赖this.radio就会变化进行重新计算,得到需要渲染的数据。
使用了按需加载后,每次进入页面时发送的请求明显变少了很多,页面的速度也相应提升了很多,页面在一两秒内就会有响应反馈,后续页面报表陆续加载完成,最终在六七秒时候全部加载完成。
虽然性能表现不算多优秀,不过相比没有优化前五六秒才有感知,现在一两秒就能给用户感知反馈已经不错了,毕竟这个页面使用到了这么多个iframe。
前期因为项目赶时间,所以使用了iframe,不过后期放弃直接用iframe的方案,自己写页面。
总结
这次的优化其实并不难,因为这次的场景比较极端,因此问题比较容易发现,解决问题的关键就是要先发现问题,这样才能对症下药,拿出合理的方案。
这次造成性能问题的主要问题是使用到了iframe嵌入页面和对v-show不合理的应用, 一次性发送过多网络请求导致性能慢,从这可以看出网络对性能的影响是非常大的,性能优化方面网络是一个重头,像常见的优化方案比如说精灵图、使用字体图标、懒加载、按需加载、使用缓存、减小打包产物体积、使用CDN等方案都是为了优化网络。
iframe虽然方便,但是的缺点还是比较多的,每个iframe都会单独加载资源,会使网络请求增多,能不用就不用。