记一次有意思的性能优化
# 记一次有意思的性能优化
这几天针对资产系统的会签流程进行了部分重构,但在重构过程中,总是遇到页面卡顿、点击页面无响应或者等好半天页面才调跳转的问题。这样子的交互和页面渲染,让人很难受,更别说调试代码了,遂进行了页面渲染性能问题进行了排查和分析。
# 问题复现
具体问题如下图所示:
可以看到,当点击进入 新增页面后,选择资产 的组件就已经在开始请求大量图片了,而且是高清图片,请求资源的量级也是没有上限的,这就导致了页面一直下载图片资源,造成了浏览器抢占资源和线程的问题出现,导致点击菜单和页面无响应问题。
# 分析问题
数据来源分析
- 首选查看了请求资产列表的接口,见如下截图:
可以看到 type-page 是个分页接口,但返回的数据量明显不是分页的数据,而更像是一个list集合,把所有的数据一起返回了,这样做会造成服务器額外的性能浪费,另一个页面渲染数据也会变慢,如果不使用缩略图的话。
- 首选查看了请求资产列表的接口,见如下截图:
业务组件加载图片的方式,见如下截图:
采用了直接使用加载原图的方式,而原图则是高清的图片,一般都有4M~7M左右,那么加载图片直接是http方式请求,就会造成资源抢占,线程堵塞的问题,导致页面卡顿无响应。
代码层面优化重构
public async onSave() {
let message = this.service.getPureText();
if (!this.noCheck && !this.selection.length) {
return this.$message.warning("请选择处理人");
}
const users = this.selection.$clone();
d
let params: any = {
recordId: this.recordId,
message: message,
taskId: this.taskId,
nodeInfo: {
targetNodeId: "",
participants: [
{
type: "",
value: ""
}
]
}
};
let voteusers: Array<any> = users.map(user => {
return { type: user.type, value: user.id };
});
params = { ...params, nodeInfo: { targetNodeId: users[0].nodeId, participants: voteusers }};
// if(users) {
// params = {
// ...params,
// nodeInfo: {
// targetNodeId: users[0].nodeId,
// participants: [
// {
// type: users[0].type,
// value: users[0].id
// }
// ]
// }
// };
// }
this.isLoading = success;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
可以看到,此块代码
let voteusers: Array<any> = users.map(user => {
return { type: user.type, value: user.id };
});
params = { ...params, nodeInfo: { targetNodeId: users[0].nodeId, participants: voteusers }};
2
3
4
是对注释区域的重构。现在我们应提倡 FP(函数式编程)思想的运用,一是可以大量简化代码,二是代码实现逻辑清晰明了,三是还可以装下13。^_^
# 解决问题
显然,从上面分析的可知
优化资产分页请求接口
图片加载的方式,尽量采用缩略图的方式加载,节省资源,避免线程堵塞问题
简化代码,使之业务逻辑清晰明了
附上最终优化后的效果
# 重构时遇到的难题
重构缩略图组件时,需要监听图片弹窗关闭的事件,但在网上找了很多资料,都没有看到 v-viewer 的弹窗关闭事件的处理,后来再仔细查阅 v-viewer 的API后,发现其是继承了viewer.js的相关属性和方法,而且是可以通过options传参解决的。最后附上自己的解决方法:
<div :class="['thumbnail', fixClassName]">
<div class="thumbnail-img">
<img
:src="thumbnail"
:key="thumbnail"
loading="lazy"
@click.stop="showViewer"
@error="onHandleError"
/>
</div>
<!--v-viewer注册为全局组件-->
<viewer
v-if="data.show"
:images="images"
@inited="initViewer"
:options="options"
style="display:none">
<img
class="image"
v-for="(image, index) in images"
:src="image"
:key="image"
@error="onHandleError"
/>
<template v-if="!images.length">
<div class="empty-message">暂无图片</div>
</template>
</viewer>
</div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@charset "UTF-8";
.thumbnail {
@include size;
position: relative;
&-img {
@include size;
cursor: pointer;
> img {
height: 100%;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Vue, Component, Prop } from "vue-property-decorator";
// import { randomPics } from "@/common";
import "./index.scss";
@Component({
template: require("./index.html")
})
export default class ThumbNailViewer extends Vue {
public viewer: any = {};
@Prop({ default: () => new Object() })
public data!: any;
@Prop({ type: String, default: () => "" })
public thumbnail!: string;
@Prop({ type: String, default: () => "" })
public fixClassName!: string;
@Prop({ type: [Array, String], default: () => [] })
public images!: Array<any> | any;
@Prop({ default: () => require("@/assets/images/common/error/error-image.png") })
public errorImg!: any;
public options: any = {
hide: () => this.onViewerHide()
};
public initViewer (viewer: any) {
this.viewer = viewer;
// console.dir(this.viewer);
}
public showViewer() {
this.$set(this.data, "show", true);
// this.images = randomPics(5).map((g: any) => g.source);
if(!this.viewer) return;
this.$nextTick(() => {
this.viewer.show();
});
}
public onViewerHide() {
this.$set(this.data, "show", false);
}
public onHandleError(evt: any) {
let img = evt.srcElement;
img.src = this.errorImg;
img.onerror = null; // 防止闪图
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Make sure to add code blocks to your code group
# 小结
性能优化前路漫漫,但我始终相信,一个有心人,总会看到不一样的细节。
只要坚持付出,总会有不同色彩的收获。