Demo address
Go to the demo address first
https://codepen.io/firstblood93/pen/QWqgVJL
Project Background
As leadership-oriented programming becomes more and more popular,
Kanban project must be a must for every front-end development expert
Product manager Zhang San asked front-end development expert
Hongdun to make a regular update of the company's financial expenditures
Red Shield operated like a tiger on
chrome
, and within two or three days, the project was completed and delivered to product manager Zhang San.
No Concurrency Control
Let's take a look at the approximate code situation of Red Shield at this time
<template>
<div class="app-container">
<div class="charts">
<div v-for="item in domList" :id="item" :key="item" class="chart" />
</div>
</div>
</template>
<script>
const echarts = require("echarts");
const chartNum = 1000; // 图表数量
const chartIntervalTime = 2000; // 图表定时渲染毫秒数
export default {
data() {
return {
domList: [],
chartObjs: {},
chartData: [150, 230, 224, 218, 135, 147, 260],
};
},
mounted() {
// 创建echart并绘图
this.createChart();
// 隔3秒更新图表数据并渲染
this.intervalChartData(chartIntervalTime);
},
methods: {
// 创建echart并绘图
async createChart() {
for (let i = 1; i <= chartNum; i++) {
this.domList.push("chart" + i);
}
this.$nextTick(this.renderChartList);
},
async renderChartList() {
this.domList.forEach((dom) => this.initChart(dom));
},
// 隔3秒更新图表数据并渲染
intervalChartData(s) {
setInterval(() => {
this.renderChartList();
}, s);
},
// 初始化图表
initChart(domId) {
if (!this.chartObjs[domId]) {
this.chartObjs[domId] = echarts.init(document.getElementById(domId));
}
const option = {
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
yAxis: {
type: "value",
},
series: [
{
data: this.chartData,
type: "line",
},
],
};
this.chartObjs[domId].clear();
this.chartObjs[domId].setOption(option);
},
},
};
</script>
<style scoped>
.chart {
float: left;
width: 360px;
height: 300px;
margin: 10px;
border: 2px solid #ff9900;
}
</style>
As a result, Zhangsan played cards according to the routine, secretly installed a browser on the TV (extremely poor performance), and then entered the address
xxx.com
(self-improvement)...
the browser... Yes, 161e939ba2430b Red Shield's heart at this time
This time he thought of the back-end big brother Huang, Huang gave him an idea
concurrency control
Implement control concurrency
implements concurrent
- First, let's implement a control
concurrency function
Students who want to go directly to the theme can skip directly to complete code
/**
* @params {Number} poolLimit -最大并发限制数
* @params {Array} array -所有的并发请求|渲染数组
* @params {Function} iteratorFn -对应执行的并发函数(接受 array 的每一项值)
*/
async function asyncPool(poolLimit, array, iteratorFn) {
const ret = [] // 所有执行中的 promises
let executing = [] // 正在执行中的 promises
for (const item of array) {
//接受 iteratorFn 的返回值:Promise
const p = Promise.resolve().then(() => iteratorFn(item))
ret.push(p)
// 如果执行的数组 大于等于 最大并发限制 那么我们就要控制并发
if (array.length >= poolLimit) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
// p.then 返回的 一个Promise 我们把它放到正在执行数组中,一旦执行完 便剔除对应的值
executing.push(e)
//核心代码:正在执行的 promises 数组 大于等于 `最大并发限制` 用.race 方法释放一个执行最快的
if (executing.length >= poolLimit) await Promise.race(executing)
}
}
//返回一个 Promise.all
return Promise.all(ret)
}
Retrofit
renderChartList
function (core)
async renderChartList() { // 这里的 MAX_CURRENT 之后可以自定义一个数字 await asyncPool(MAX_CURRENT, this.domList, (dom) => { // 我们在这里必须返回一个 promise 对应为 `并发函数` 的 `p` 变量 return new Promise(async (resolve) => { const res = await this.initChart(dom); resolve(res);// 这一步之后, 对应执行 `并发函数` 的 p.then 剔除 }).then((data) => { console.log(data); return data; }); }); }
3. initChart
function
We must ensure a chart rendering is complete, the next and then perform a rendering, then we need to listen Echarts
of finished
event
initChart(domId) {
// 我们 把它改造成一个 promise 函数
return new Promise((resolve) => {
...
// 核心代码 监听 echarts 的 finished
this.chartObjs[domId].on("finished", () => {
resolve(domId);// 对应 上一步的 `const res = await this.initChart(dom);`
});
});
}
4. intervalChartData
function
We must ensure that all graph renderings are executed concurrently before entering the next timer logic
It is executing
to judge the length of 061e939ba244ee (at this time, executing
should be independent as a global variable)
intervalChartData(s) {
setInterval(() => {
if (executing.length > 0) return; // 还有正在执行的渲染 不重复添加
this.renderChartList();
}, s);
}
full code
Attach complete code
<template>
<div class="app-container">
<div class="charts">
<div v-for="item in domList" :id="item" :key="item" class="chart" />
</div>
</div>
</template>
<script>
const echarts = require("echarts");
const chartNum = 1000; // 图表数量
const MAX_CURRENT = 50; // 图表最大渲染并发数
const chartIntervalTime = 2000; // 图表定时渲染毫秒数
let executing = [];
/**
* @params {Number} poolLimit -最大并发限制数
* @params {Array} array -所有的并发请求|渲染数组
* @params {Function} iteratorFn -对应执行的并发函数(接受 array 的每一项值)
*/
async function asyncPool(poolLimit, array, iteratorFn) {
const ret = []; // 所有执行中的 promises
executing = []; // 正在执行中的 promises
for (const item of array) {
const p = Promise.resolve().then(() => iteratorFn(item));
ret.push(p);
if (array.length >= poolLimit) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= poolLimit) await Promise.race(executing);
}
}
return Promise.all(ret);
}
export default {
data() {
return {
domList: [],
chartObjs: {},
chartData: [150, 230, 224, 218, 135, 147, 260],
};
},
mounted() {
// 创建echart并绘图
this.createChart();
// 隔3秒更新图表数据并渲染
this.intervalChartData(chartIntervalTime);
},
methods: {
// 创建echart并绘图
async createChart() {
for (let i = 1; i <= chartNum; i++) {
this.domList.push("chart" + i);
}
this.$nextTick(this.renderChartList);
},
async renderChartList() {
const res = await asyncPool(MAX_CURRENT, this.domList, (i, arr) => {
return new Promise(async (resolve) => {
const res = await this.initChart(i);
resolve(res);
}).then((data) => {
console.log(data);
return data;
});
});
},
// 隔3秒更新图表数据并渲染
intervalChartData(s) {
setInterval(() => {
if (executing.length > 0) return; // 还有正在执行的渲染 不重复添加
this.renderChartList();
}, s);
},
// 初始化图表
initChart(domId) {
return new Promise((resolve) => {
if (!this.chartObjs[domId]) {
this.chartObjs[domId] = echarts.init(document.getElementById(domId));
}
const option = {
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
yAxis: {
type: "value",
},
series: [
{
data: this.chartData,
type: "line",
},
],
};
this.chartObjs[domId].clear();
this.chartObjs[domId].setOption(option);
this.chartObjs[domId].on("finished", () => {
resolve(domId);
});
});
},
},
};
</script>
<style scoped>
.chart {
float: left;
width: 360px;
height: 300px;
margin: 10px;
border: 2px solid #ff9900;
}
</style>
Easter eggs
Little Easter Egg✌️, Red Shield persuaded
Zhang San to buy a high-performance TV, the perfect solution...
wrong, please correct me 🌟 find it helpful, welcome to 🌟
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。