【问题标题】:JavaScript Generator: implement a ticket queue systemJavaScript Generator:实现票务队列系统
【发布时间】:2021-04-21 14:22:44
【问题描述】:

我正在尝试实现一个工单队列系统,默认情况下它将有 3 个不同的队列来持有分别为严重性 1、严重性 2 和严重性 3 的工单。我有一个方法getTicketAtHighestSeverity,它返回最高严重性队列中最旧的票证,所以它从第一个队列开始,查找队列中的第一项,如果当前队列为空,则移动到下一个队列,并且另一种方法getTicketBySeverity 遍历所有队列返回从最高严重性开始的票

这是我的实现。

class ticketQueues {
    constructor(numOfQueues = 3) {
        this.queues = Array.from({length: numOfQueues}).fill([])
    }

    addSev1(ticket) {
        this.queues[0].push(ticket)
    }

    addSev2(ticket) {
        this.queues[1].push(ticket)
    }

    addSev3(ticket) {
        this.queues[2].push(ticket)
    }

    *getTicketBySeverity() {
        for(const queue of this.queues) {
            for(const ticket of queue) {
                yield ticket
            }
        }

        return null
    }

    getTicketAtHighestSeverity() {
        for(const queue of this.queues) {
            for(const ticket of queue) {
                return ticket
            }
        }
        
        return null
    }

}

但是,getTicketBySeverity 似乎无法正常工作。


const queues = new ticketQueues()
queues.addSev1({timestamp: Date(), name: 't1'})
queues.addSev2({timestamp: Date(), name: 't2'})
queues.addSev3({timestamp: Date(), name: 't3'})

for(let i = 2; i >= 0; i--) {
    console.log(queues.getTicketBySeverity().next().value) // ???? this keeps returning the first item from the queue
}


因为它不会移动到下一张票,因为它只返回第一张票。我选择 Generator 来实现这种方法的原因是我想利用惰性评估模型,因为数据集可能很大,我不想一次获得所有票。

有人可以用getTicketBySeverity 修复我的实现吗?关于这里的命名有什么建议吗?我觉得这里的命名,即getTicketBySeveritygetTicketAtHighestSeverity 可能不是最佳选择。此外,如果您认为这可能不是一个合法的用例,请随时评论我对 Generator 的使用。

【问题讨论】:

  • 您不断地通过调用queues.getTicketBySeverity() 来创建新的迭代器——每个迭代器都将从第一张票开始。该方法的实现非常好(尽管return null 似乎相当不必要)。
  • @Bergi 谢谢这确实是这里发生的事情!

标签: javascript oop ecmascript-6 generator


【解决方案1】:

一个问题是

this.queues = Array.from({length: numOfQueues}).fill([])

.fill(通常)不适用于非基元,因为新数组中的每个项目都是对同一对象的引用。您只创建了一个数组。问题与为什么以下内容无法正常工作的原因相同:

const subarr = [];
arr.push(subarr);
arr.push(subarr);

因为只有一个subarr

使用带有Array.from 的映射器函数为每次迭代显式创建一个新数组:

this.queues = Array.from({length: numOfQueues}, () => []);

此外,要遍历迭代器,请使用 for..of - 或者在找到时从数组中删除找到的项(否则,每次调用它时,它都会返回相同的项)。

您可以使用for..of 控制一次移除的票证数量,方法是向生成器传递一个参数并跟踪产生的元素数量:

class ticketQueues {
    constructor(numOfQueues = 3) {
        this.queues = Array.from({length: numOfQueues}, () => []);
    }

    addSev1(ticket) {
        this.queues[0].push(ticket)
    }

    addSev2(ticket) {
        this.queues[1].push(ticket)
    }

    addSev3(ticket) {
        this.queues[2].push(ticket)
    }
    *getTicketsBySeverity(limit) {
        let count = 0;
        for(const queue of this.queues) {
            while (queue.length) {
                yield queue.shift();
                count++;
                if (count === limit) {
                    return null;
                }
            }
        }
        return null
    }
}



const queues = new ticketQueues()
queues.addSev1({timestamp: Date(), name: 't1'})
queues.addSev1({timestamp: Date(), name: 't1-2'})
queues.addSev2({timestamp: Date(), name: 't2'})
queues.addSev3({timestamp: Date(), name: 't3'})

for (const ticket of queues.getTicketsBySeverity(3)) {
  console.log(ticket);
}
console.log(queues.queues);

【讨论】:

  • 我试图打印出这部分 Array.from({length: numOfQueues}).fill([]) 并且看起来非常好,即 [[], [], []] 也 yoru for of 循环与生成器函数一起使用,但它有点违背了这里的目的。我用生成器实现它的原因是为了避免运行到完成的行为,这样我就可以控制我想从队列中拉出多少票。有没有办法不循环到队列的末尾?
  • 对不起,你是对的 `Array.from({length: numOfQueues}).fill([])` 确实会导致问题
  • 如果您想控制移除的票证数量,请传递一个参数并跟踪到目前为止移除的项目数量,以便您可以在需要时返回。
  • 我看到你更新了 sn-p。感谢您的建议!我在这里codereview.stackexchange.com/questions/254810/… 发布了一个完整的代码审查实施方案。有时间可以看看吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多