NodeJS 如何在JavaScript中实现具有任务优先级的基于Promise的队列?

06odsfpq  于 2023-06-05  发布在  Node.js
关注(0)|答案(1)|浏览(213)

我尝试在JavaScript中构建一个基于promise的队列,其中每个任务都返回一个promise,该promise在任务完成时解析。队列应该一次处理一个任务,等待每个promise解决后再开始下一个。
然而,这里有一个复杂性:每个任务都有一个优先级,高优先级的任务应该跳过队列。如果添加了优先级较高的任务,则该任务应该是当前运行的任务完成后要运行的下一个任务,而不管它在队列中的位置如何。
下面是一个简单的例子:

class Task {
  constructor(fn, priority) {
    this.fn = fn;
    this.priority = priority;
  }
}

class PriorityPromiseQueue {
  // implementation needed
}

PriorityPromiseQueue应该处理Task对象,按优先级顺序调用每个Task.fn函数。Task.fn将返回一个promise。
有没有人对如何实现这个PriorityPromiseQueue有什么建议?我考虑过使用数组并按优先级排序,但我想知道是否有更有效的方法,特别是对于大量任务。

yduiuuwa

yduiuuwa1#

最简单的实现方式可能是这样的。是的,它仍然是一个排序数组。AFAIK当前的JS实现使用自适应的https://en.wikipedia.org/wiki/Timsort,因此将新任务插入到已经排序的队列是线性的。
原因是我怀疑一个promise队列是否会有超过10000个项目。真实的案例场景将完全可以与它imho。

class Task {
    constructor(fn, priority) {
        this.fn = fn;
        this.priority = priority;
    }
}

class PriorityPromiseQueue {

    tasks = []
    constructor(...queue) {
        this.add(...queue);
    }
    add(...queue) {

        const sort = () => this.tasks.sort((a, b) => b.priority - a.priority);

        // allow change priority at runtime and resort the queue
        queue.forEach(task => {

            let priority = task.priority;

            Object.defineProperty(task, 'priority', {
                get: () => priority,
                set: val => {
                    priority = val;
                    sort();
                }
            });

        });
        this.tasks.push(...queue);
        sort();

    }
    remove(task) {
        const idx = this.tasks.indexOf(task);
        if (idx === -1) {
            return false; // not in the queue
        }
        Object.defineProperty(task, 'priority', {
            value: task.priority
        });
        this.tasks.splice(idx, 1);
        return true;
    }
    async run() {
        if (!this.tasks.length) {
            return;
        }
        const task = this.tasks.shift();
        await task.fn();
        return this.run();
    }

}

let taskId = 1;
const createTask = () => {
    const id = taskId++;
    return new Task(
        () => new Promise(resolve => setTimeout(
            () => console.log('task', id, 'complete') + resolve(),
            Math.random() * 3000
        )),
        Math.random()
    );
};

const tasks = Array.from({ length: 5 }, _ => createTask());

const queue = new PriorityPromiseQueue(...tasks);

queue.run().then(() => console.log('QUEUE COMPLETE'));

//move the last task to the top after running the queue so the 5th task should be 1st or 2nd
tasks.at(-1).priority = 1;

// add and remove tasks at run time
const task = createTask();
queue.add(task);
queue.add(createTask());
queue.remove(task);

相关问题