实现一个带并发限制的promise异步调度器
之前看到这个题目,实现一个带并发限制的promise异步调度器,觉得挺有意思,在这里记录一下。
题目是什么意思呢,就是我们正常情况下,promise是没有并发数量限制的,同一个时间可以多个请求同时执行,然后谁返回的速度快,在前端页面直观的就可以打印谁的返回内容。
1 class Scheduler { 2 constructor() {} 3 add(promise) { 4 this.runTask(promise); 5 } 6 runTask(promise) { 7 promise().then(res => { 8 console.log(res); 9 }); 10 } 11 } 12 13 const scheduler = new Scheduler(); 14 const timeout = (time, order) => { 15 return new Promise(resolve => { 16 setTimeout(() => { 17 resolve(order); 18 }, time); 19 }); 20 }; 21 const addTask = (time, order) => { 22 scheduler.add(() => timeout(time, order)); 23 }; 24 addTask(4000, 1); 25 addTask(1000, 2); 26 addTask(900, 3); 27 addTask(3000, 4);
ok,那我们现在来限制并发数量,假定并发数量最大是2。什么意思呢,就是我们上面例子中,执行任务的盒子,第一个addTask可以放进去,第二个也可以放进去,但第三个不可以立马放进去,因为最大并发数量是2,需要过1000ms,等第二个addTask执行完毕后,那此刻执行任务盒子里只有1个盒子,可以把第三个放进。。。。
那我们来改改 Scheduler。
1 class Scheduler { 2 constructor() { 3 this.max = 2;// 最大限制数 4 this.work = [];// 正在执行的任务盒子 5 this.unwork = [];// 等待的任务盒子 6 } 7 add(promise) { 8 if (this.work.length < this.max) { 9 //还没达到最大数量限制,可以直接执行 10 this.runTask(promise); 11 } else { 12 // 此时任务盒子数量达到并发最大数量,那就放在等待区域 13 this.unwork.push(promise); 14 } 15 } 16 runTask(promise) { 17 this.work.push(promise); 18 promise() 19 .then(res => { 20 console.log(res); 21 }) 22 .finally(() => {
// 任务执行完毕,就立马从执行任务盒子删掉 23 let index = this.work.indexOf(promise); 24 this.work.splice(index, 1);
// 如果任务等待盒子还有任务,那就继续执行 25 if (this.unwork.length) { 26 this.runTask(this.unwork.shift()); 27 } 28 }); 29 } 30 } 31 32 const scheduler = new Scheduler(); 33 const timeout = (time, order) => { 34 return new Promise(resolve => { 35 setTimeout(() => { 36 resolve(order); 37 }, time); 38 }); 39 }; 40 const addTask = (time, order) => { 41 scheduler.add(() => timeout(time, order)); 42 }; 43 addTask(4000, 1); 44 addTask(1000, 2); 45 addTask(900, 3); 46 addTask(3000, 4); 47
我们在打印的内容加个时间,看看每个任务都是过了多久才执行打印出来的。
1 let date = null; 2 class Scheduler { 3 constructor() { 4 this.max = 2; 5 this.work = []; 6 this.unwork = []; 7 } 8 add(promise) { 9 if (this.work.length < this.max) { 10 this.runTask(promise); 11 } else { 12 this.unwork.push(promise); 13 } 14 } 15 runTask(promise) { 16 if (!date) { 17 date = performance.now(); 18 } 19 this.work.push(promise); 20 promise() 21 .then(res => { 22 let now = performance.now(); 23 let subdate = now - date; 24 /* 处理一下这个时间间隔,因为会多有几十毫秒,处理其他逻辑,如addTask等 */ 25 subdate = (subdate / 100).toFixed(0) * 100; 26 console.log('经过多久打印:', subdate, '打印值为:', res); 27 }) 28 .finally(() => { 29 let index = this.work.indexOf(promise); 30 this.work.splice(index, 1); 31 if (this.unwork.length) { 32 this.runTask(this.unwork.shift()); 33 } 34 }); 35 } 36 } 37 38 const scheduler = new Scheduler(); 39 const timeout = (time, order) => { 40 return new Promise(resolve => { 41 setTimeout(() => { 42 resolve(order); 43 }, time); 44 }); 45 }; 46 const addTask = (time, order) => { 47 scheduler.add(() => timeout(time, order)); 48 }; 49 addTask(4000, 1); 50 addTask(1000, 2); 51 addTask(900, 3); 52 addTask(3000, 4);