zoukankan      html  css  js  c++  java
  • 由一道面试题引出的前端永动机问题

    最近有看到这样一道面试题。
     
    大概意思是一个promise管理组件,所有的对外的请求都走该组件。然后要求该组件对请求进行管理。实现的效果是同一时刻只能有2个请求在进行,不满2个就会发出新的请求。
    这道题一开始我的思路是肯定有一个promise的收集器,然后对收集的promise进行管理,一开始肯定要发出2个请求,然后关键是一个请求结束之后发出新的请求,保证2个请求一直在进行中。我是通过promise的trace发出2个请求的,然后只要有一个返回就再发出一个新的请求。
     
    但是显然我的这个思路有一个问题:解决了需求的发出,只解决了发出;没有注意到需求一直进来的,按照我的思路是无法实现对进来需求的管理,只是一个一次性的发出方案。
     
    后来借鉴了一些思路。然后明白了该怎么解决。
     
    其实这个组件里面是需要有一套独立的逻辑的,这套逻辑就是用来处理进来的请求以及保证2个请求同时进行。外部显然是持续进来,既然是持续进来内部要一套类似事件循环的机制,类似一种待机状态,只要满足需求就开始运转起来。
     
    我发现这种机制有点类似永动机。只不过是一种有条件的永动机。在前端实现永动机的机制有两种方法:一种利用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需要在组件失效时候清除就好了。
     
    这道题给我的启示是:对复杂场景的开发解决方案给出还不足,对开发内在的一些逻辑还能够更好的去应用,可以主动找一些复杂的开发场景学习学习。

    我站在山顶看风景!下面是我的家乡!
  • 相关阅读:
    MYSQL5.7.11安装问题
    Controllerizing the ScrollViewer Thumbnail
    WPF Tutorial
    How to properly release Excel COM objects
    How to detect and avoid memory and resources leaks in .NET applications
    [Forward]Ten Caching Mistakes that Break your App
    Process.StandardOutput
    .NET Framework posters with Namespaces & Types
    【转】常用 Microsoft .NET Framework 各版本下載網址列表
    6 ways to import data into SQL Server
  • 原文地址:https://www.cnblogs.com/zhensg123/p/14618339.html
Copyright © 2011-2022 走看看