#javascript #oop #ecmascript-6 #generator
#javascript #ооп #ecmascript-6 #генератор
Вопрос:
Я пытаюсь внедрить систему очереди заявок, где по умолчанию у нее будет 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
. И какие-либо предложения по поводу именования здесь? Я чувствую, что именование здесь, т.е. getTicketBySeverity
и getTicketAtHighestSeverity
, Возможно, не лучший выбор. Кроме того, не стесняйтесь комментировать мое использование Generator здесь, если вы считаете, что это может быть неправильным вариантом использования для этого.
Комментарии:
1. Вы продолжаете создавать новые итераторы, вызывая
queues.getTicketBySeverity()
снова и снова — каждый из них будет начинаться с первого билета. Реализация метода в полном порядке (хотяreturn null
кажется довольно ненужной).2. @Bergi спасибо, это действительно то, что здесь происходит!
Ответ №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);
Комментарии:
1. Я попытался распечатать эту часть
Array.from({length: numOfQueues}).fill([])
, и она выглядит отлично, т.Е.[[], [], []]
for of
Цикл yoru также работает с функцией генератора, но здесь это как бы противоречит цели. Причина, по которой я реализовал это с помощью generator, заключается в том, чтобы избежать поведения от запуска до завершения, чтобы я мог контролировать, сколько заявок я хотел извлечь из очередей. Есть ли способ не перебирать путь до конца очереди?2. извините, на самом деле вы правы ` Array.from({length: numOfQueues}).fill([])` действительно вызывает проблему здесь
3. Если вы хотите контролировать количество удаленных заявок, передайте аргумент и отслеживайте количество удаленных элементов, чтобы вы могли вернуться, когда это необходимо.
4. Я вижу, вы обновили фрагмент. спасибо за предложения! Я опубликовал полное руководство для обзора кода здесь codereview.stackexchange.com/questions/254810 /. … не могли бы вы взглянуть, если у вас есть время?