Генератор JavaScript: реализация системы очереди заявок

#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 /. … не могли бы вы взглянуть, если у вас есть время?