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需要在组件失效时候清除就好了。
     
    这道题给我的启示是:对复杂场景的开发解决方案给出还不足,对开发内在的一些逻辑还能够更好的去应用,可以主动找一些复杂的开发场景学习学习。

    我站在山顶看风景!下面是我的家乡!
  • 相关阅读:
    简单的模板解析函数
    HTML通过事件传递参数到js 二 event
    HTML通过事件传递参数到js一
    通过this获取当前点击选项相关数据
    LeetCode 20. 有效的括号(Valid Parentheses)
    LeetCode 459. 重复的子字符串(Repeated Substring Pattern)
    LeetCode 14. 最长公共前缀(Longest Common Prefix)
    LeetCode 168. Excel表列名称(Excel Sheet Column Title)
    LeetCode 171. Excel表列序号(Excel Sheet Column Number) 22
    LeetCode 665. 非递减数列(Non-decreasing Array)
  • 原文地址:https://www.cnblogs.com/zhensg123/p/14618339.html
Copyright © 2011-2022 走看看