一、背景
因为电脑 CPU、内存等的限度,可能同时启动的工作数有肯定限度,例如一台电脑可能执行 5 个异步工作,然而目前有 100 个异步工作要执行,那么如何让这 100 个工作无距离的疾速执行结束呢?
二、问题解答
刚遇到这个问题的时候,也是出于懵逼状态,怎么解决呢???碰巧的是近期学习了一些 Vue 的源码常识,那么是不是能够借鉴其思维来解决遇到的这个难题呢?通过一步步剖析,确定答案是必定的。上面从解题思路、知识点及代码实现来聊一聊实现过程。
2.1 解题思路
上述是整个流程图,其流程可简化为以下几个步骤:
- 将所有工作分为两组,工作组 1 指的是电脑能够并行执行的异步工作,工作组 2 指的是其余的异步工作;
- 将工作组 1 变为可帧听状态,即其发生变化时咱们可能晓得;
- 将工作组 1 中的工作触发(不触发工作不会执行);
- 某一工作执行结束后,将工作组 2 中的一个工作填充到可帧听状态的工作组 1 中;
-
工作依照固定数量一直执行,直到所有工作执行结束。
2.2 知识点
在 Vue 源码中,Vue2.x 应用 Object.defineProperty() 实现对数据的帧听;Vue3.0 应用 Proxy 实现对数据的帧听。本着赶时髦和 Proxy 的确优良的态度,在实现过程中也利用了 Proxy。Proxy 作为一个新的知识点,先理解一下其定义及应用办法。
2.2.1 定义
Proxy 中文意思是“代理”,是在指标对象之间架设一层“拦挡”,从而能够批改某些操作的默认行为。Proxy 共反对十三种拦挡操作:get、set、has、deleteProperty、ownKeys、getOwnPropertyDescriptor、defineProperty、preventExtensions、getPrototypeOf、isExtensible、setPrototypeOf、apply、construct。
2.2.2 简略应用
function testProxy(obj) { return new Proxy(obj, {get: (target, key) => {console.log(` 我被 get 拦截器拦挡了,拦挡的属性是 ${key}`); }, set: (target, key, value) => {console.log(` 我被 set 拦截器拦挡了,拦挡的属性是 ${key}, 新值是 ${value}`); target[key] = value; } }); } const testObj = {a: 10}; const proxy = testProxy(testObj); proxy.a = 100;
2.2.3 具体应用
具体用法能够参考阮一峰大佬的“ECMAScript 6 入门”。
2.3 代码实现
2.3.1 定义两个工作队列
首先定义两个工作队列,task1 为开始执行的一批工作,task2 中为后续增加进去的工作。
const task1 = [1, 2, 3]; const task2 = [4, 5, 6, 7, 8];
2.3.2 数据变为可帧听的函数
利用 Proxy 将数据变为可帧听状态
/** * 监听模块,监听对应数组的变动,保障其始终有肯定长度的内容在运行 * * @param {Array} initArr 定长工作的数组 * @param {Function} callback 对应的回调函数 */ function watcher(initArr, callback) { const proxy = new Proxy(initArr, {set(target, key, value, receiver) {target[key] = value; callback(value, key, receiver); } }); return proxy; }
2.3.3 异步工作逻辑
/** * 异步工作的运行逻辑 * * @param {number} taskIndex 异步工作的序号 * @param {number} index 当前任务在定长工作的序号 * @param {Proxy} proxy Proxy 实例 */ function asyncTask(taskIndex, index, proxy) {console.log(`${index} 索引处的工作 ${taskIndex} 开始执行 `); return new Promise(resolve => {setTimeout(() => {console.log(`${index} 索引处的工作 ${taskIndex} 执行结束 `); // 当工作队列 2 中还有工作时,进入队列替换工作 1 中执行完的工作 if (task2.length > 0) {proxy[index] = task2.shift();} }, 1000 + 2000 * Math.random()); }); }
2.3.4 主函数
const proxy = watcher(task1, asyncTask); task1.forEach((taskIndex, index) => asyncTask(taskIndex, index, proxy)); }
2.3.5 执行后果
通过后果能够看到,当一个工作实现时立即将有一个新的工作进入。
0 索引处的工作 1 开始执行 1 索引处的工作 2 开始执行 2 索引处的工作 3 开始执行 0 索引处的工作 1 执行结束 0 索引处的工作 4 开始执行 2 索引处的工作 3 执行结束 2 索引处的工作 5 开始执行 1 索引处的工作 2 执行结束 1 索引处的工作 6 开始执行 0 索引处的工作 4 执行结束 0 索引处的工作 7 开始执行 2 索引处的工作 5 执行结束 2 索引处的工作 8 开始执行 1 索引处的工作 6 执行结束 0 索引处的工作 7 执行结束 2 索引处的工作 8 执行结束
三、探讨
针对此类问题的解决形式,各位大佬有新的思路与办法欢送留言,咱们一起探讨,共同进步。
1. 如果感觉这篇文章还不错,来个分享、点赞吧,让更多的人也看到
2. 关注公众号执鸢者,支付学习材料(前端“多兵种”材料),定期为你推送原创深度好文