如何在vue项目中使用Iframe使得任务分区!
一、问题描述
背景
:前两天,我和我的同事遇到一个问题,大概是这样子的,在一个项目的一个页面中使用websocket获取后台的实时数据,实时数据每一秒钟得到一条,一条数据大约有12组(可能会更多),前端需要分组将其动态的绘制到12个echarts图表中;画出来的图是基于这个图例的,也就是说,每一秒钟浏览器都需要绘制超过12个这样的图例,项目设计上是没有做分页或是其他的分页处理的;因此只能硬着头皮同时绘制在一个页面中;
问题
:问题在于,因为需求是想要看到从业务开始到业务结束的所有数据,因此socket的数据,是一直缓存在前端的;并且每一秒钟都需要进行一次绘制,所以随着时间的累计,前端的数据会是一个比较大的增量,并且随着时间的累计绘制的消耗也会越来越大,当我们绘制到第2分钟的时候,就会出现菜单卡顿的问题;
分析
:卡顿的问题其实主要是因为在每一秒钟绘制图标的过程中,本质上是js在操作canvas和执行计算的过程,所以是js线程的任务过大,阻塞了浏览器渲染线程的原因,导致浏览器无法在16ms以内有盈余去执行渲染,使得菜单的点击或是其他的操作看起来卡顿,不流畅;
解决思路
:有这样几种解决思路,第一可以分页处理,让前端缓存的数据,不要那么多,并且较少绘制的量级,比如实时绘制几个图例就好了,说白了就是任务分时;第二是因为这个业务场景是单页面应用,所以整个项目只有一个HTML,因此可以借助iframe,在vue中嵌套一个iframe,让绘制的任务在这个Iframe中执行,哪怕这个里面的任务再多,也不会影响主应用的渲染,因为他们是两个独立的域,只要解决通信问题,便能够使得我们的需求得到比较好的实现;
二、具体实现
1、文件准备
在进行实现之前,我做了一个小的Demo,初步进行了一个实验;
首先在自己项目当中的public文件夹中创建一个iframe.html,在这里面之后会写主要的绘制任务;
node_modules
|
public
| |
| iframe.html
| |
| index.html
然后创建如下的vue文件;
<template>
<div>
<h1>iframe</h1>
<button @click="move">移动</button>
<div class="div" :style="{transform:`translateX(${distence}px)`}"></div>
<iframe :src="src" frameborder="0"></iframe>
</div>
</template>
<script>
export default {
name:"Iframe",
data(){
return {
src:"http://localhost:8081/iframe.html",
distence:10
}
},
methods:{
move(){
this.distence +=100;
}
}
}
</script>
<style>
.div{
width:100px;height:100px;background-color:red;
position:relative;
transition:all 0.5s linear;
}
</style>
2、问题解释
我想解释一下,为什么这里的src要使用url而不使用相对路径或者绝对路径,因为iframe的src属性必须满足一个点就是src指向的必须是一个独立的域,因为iframe标签最终是要经过编译打包的,无论在开发环境还是生产环境,因此打包之后,在开发环境即便指向的是一个你定义好的新的HTML,但是编译之后,全都指向了当前index.html,所以会出现iframe的内容就是index.html的内容的问题;
因此我们需要将src指向一个url,直接访问到public中iframe.html的内容,这样做就可以生效;
通过这样的方式,运行这个项目应该就可以使用了;可以看到iframe的位置就是iframe.html里面的内容;
3、iframe任务
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.2.2/echarts.common.js"></script>
<style>
#echart {
width: 300px;
height: 300px;
border: 1px solid #ccc;
}
.move {
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="echart"></div>
<script>
let bar = echarts.init(document.getElementById("echart"));
let option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}]
};
bar.setOption(option);
let genData = () => {
let arr = [];
for (let i = 0; i < 10000; i++) {
arr.push(Math.ceil(Math.random() * 100))
}
return arr
}
setInterval(() => {
bar.setOption({
series: {
data: genData()
}
})
}, 1000)
</script>
</body>
</html>
4、iframe任务
在iframe引入ecahrts的cdn,然后进行绘制,可以看到,我设置的是每秒钟绘制10000条数据;可以说这个绘制的消耗还是有挑战的,但是在vue文件中去执行一个动画,移动方块;可以看到其实是并不阻塞的,因为他们完全就是在不同的域
三、总结
以上还有其他的方案,在这里就不进行一一详述了,如果有理解不合理的地方请读者指正,万分感激!