由一道面试题引出的前端永动机问题
作者:互联网
最近有看到这样一道面试题。
大概意思是一个promise管理组件,所有的对外的请求都走该组件。然后要求该组件对请求进行管理。实现的效果是同一时刻只能有10个请求在进行,不满10个就会发出新的请求。
这道题一开始我的思路是肯定有一个promise的收集器,然后对收集的promise进行管理,一开始肯定要发出10个请求,然后关键是一个请求结束之后发出新的请求,保证10个请求一直在进行中。我是通过promise的trace发出10个请求的,然后只要有一个返回就再发出一个新的请求。
但是显然我的这个思路有一个问题:解决了需求的发出,只解决了发出;没有注意到需求一直进来的,按照我的思路是无法实现对进来需求的管理,只是一个一次性的发出方案。
后来借鉴了一些思路。然后明白了该怎么解决。
其实这个组件里面是需要有一套独立的逻辑的,这套逻辑就是用来处理进来的请求以及保证10个请求同时进行。外部显然是持续进来,既然是持续进来内部要一套类似事件循环的机制,类似一种待机状态,只要满足需求就开始运转起来。
我发现这种机制有点类似永动机。只不过是一种有条件的永动机。在前端实现永动机的机制有两种方法:一种利用settimeout、setInterval;另一种是利用递归。
后来我找到了一种利用递归实现上述组件的方案:
class Scheduler { constructor() { this.queue = []; // 队列 this.maxCount = 2; // 最大并行数 this.runCounts = 0; // 请求中的数量 } add(promiseCreator) { this.queue.push(promiseCreator); } taskStart() { for (let i = 0; i < this.maxCount; i++) { this.request(); } } request() { if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) { return; } this.runCounts++; this.queue.shift()().then(() => { this.runCounts--; this.request(); }); } } const timeout = time => new Promise(resolve => { setTimeout(resolve, time); }) const scheduler = new Scheduler(); const addTask = (time, order) => { scheduler.add(() => timeout(time).then(() => console.log(order))) } addTask(1000, '1'); addTask(500, '2'); addTask(300, '3'); addTask(400, '4'); scheduler.taskStart() setTimeout(() => { addTask(1000, '5'); addTask(500, '6'); addTask(300, '7'); addTask(400, '8'); }, 2000);然后自己写了一个利用setInterval实现的方案:
class Scheduler2 { constructor() { this.queue = []; // 队列 this.maxCount = 2; // 最大并行数 this.runCounts = 0; // 请求中的数量 this.setInter = null } add(promiseCreator) { this.queue.push(promiseCreator); } taskStart() { for (let i = 0; i < this.maxCount; i++) { this.request(); } this.setInter = setInterval(() => { console.log('uuuu') this.request(); }, 0); } request() { if (!this.queue.length || this.runCounts >= this.maxCount) { return; } this.runCounts++; this.queue.shift()().then(() => { this.runCounts--; }); } destroy() { clearInterval(this.setInter) } } const timeout = time => new Promise(resolve => { setTimeout(resolve, time); }) const scheduler = new Scheduler2(); const addTask = (time, order) => { scheduler.add(() => timeout(time).then(() => console.log(order))) } addTask(1000, '1'); addTask(500, '2'); addTask(300, '3'); addTask(400, '4'); scheduler.taskStart() setTimeout(() => { addTask(1000, '5'); addTask(500, '6'); addTask(300, '7'); addTask(400, '8'); }, 1000);
但我后来想到一个问题,第一个实现方案是已经确定了promise进来的数量。我发现如果我2秒之后添加的新的请求,第一个就不在发挥作用了。换句话说第一种方案添加进请求会有一个时间上限,超过这个时间上限就失效了。 而setInterval在不考虑清除setInterval的情况下真正实现了一旦开启想什么时候进来都行。然后setInterval需要在组件失效时候清除就好了。 这道题给我的启示是:对复杂场景的开发解决方案给出还不足,对开发内在的一些逻辑还能够更好的去应用,可以主动找一些复杂的开发场景学习学习。
标签:addTask,面试题,const,请求,引出,runCounts,queue,time,永动机 来源: https://www.cnblogs.com/zhensg123/p/14618339.html