Demo 地址
先上 demo 地址
https://codepen.io/firstblood...
我的项目背景
随着 面向领导编程
越来越深入人心, 看板
我的项目想必是每个前端开发专家的必修之路
产品经理 张三
要求 前端开发专家 红盾
做一个由 1000个图表定时刷新
的公司最新的财务收入状况
红盾
在 chrome
上 一顿操作猛如虎,没两三天就把 我的项目搞定了 交付给产品经理 张三
.
无并发管制
让咱们来看看 红盾
此时大抵的代码状况
<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>
后果 张三
不按套路出牌, 在电视机上偷偷安了个 浏览器(性能极差),而后输出地址 xxx.com
(自行脑补)...
间接把浏览器给淦奔溃了...没错, 红盾
此时的心田
这时候 他想起了 后端大佬 老黄
,老黄给了他一个思路 管制并发
实现管制并发
实现并发
- 首先咱们来实现一个管制
并发函数
想间接进入主题的同学能够间接跳到 残缺代码
查看
/** * @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)}
革新
renderChartList
函数(外围
)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
函数
咱们必须保障一个图表渲染实现,再执行下一个渲染,此时咱们就须要监听 Echarts
的 finished
事件
initChart(domId) { // 咱们 把它革新成一个 promise 函数 return new Promise((resolve) => { ... // 外围代码 监听 echarts 的 finished this.chartObjs[domId].on("finished", () => { resolve(domId);// 对应 上一步的 `const res = await this.initChart(dom);` }); });}
4.革新 intervalChartData
函数
咱们必须保障并发执行完 所有的图表渲染,再进入下一个定时器逻辑
判断 executing
的长度即可(此时应该把 executing
独立为全局变量)
intervalChartData(s) { setInterval(() => { if (executing.length > 0) return; // 还有正在执行的渲染 不反复增加 this.renderChartList(); }, s);}
残缺代码
附上残缺代码
<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>
小彩蛋
小彩蛋✌️, 红盾
压服张三
买了个高性能的电视机 完满解决...
如有不对,欢送斧正 感觉有帮忙,欢送三连