javascript 节点排队作业

kxeu7u2r  于 2023-03-28  发布在  Java
关注(0)|答案(1)|浏览(127)

我有一个MethodQueue类,它将方法排入队列数组并执行它们。这里的棘手部分是,我想一次执行一个作业,下一个作业必须在前一个完成后的x秒后开始,以避免在任何时间内超过请求。
所以我就这样实现了MethodQueue类。

class MethodQueue {
    private queue: (() => Promise<any>)[] = [];
    private isExecuting = false;

    async enqueue(method: () => Promise<any>): Promise<void> {
        this.queue.push(method);
        if (!this.isExecuting) {
            this.executeNext();
        }
    }
    private async executeNext(): Promise<void> {
        if (this.isExecuting) return;
        this.isExecuting = true;
        const method = this.queue.shift();
        if (method) {
            await method();
            this.isExecuting = false;
            setTimeout(() => this.executeNext(), 1000);
        } else {
            this.isExecuting = false;
        }
    }
}

我有一个SendQueue类,其中包含我从其他文件中使用的静态方法。

export class SendQueue {
    private static methodQueue = new MethodQueue();

    public static async m1(param1: string, param2: number): Promise<string> {
        return new Promise<string>((resolve) => {
            SendQueue.methodQueue.enqueue(async () => {
                const result = await Send.m1(param1, param2);
                resolve(result);
            });
        });
    }

    public static async m2(param1: string): Promise<string> {
        return new Promise<string>((resolve) => {
            SendQueue.methodQueue.enqueue(async () => {
                const result = await Send.m2(param1);
                resolve(result);
            });
        });
    }

    public static async m3(param1: string, param2: boolean): Promise<string> {
        return new Promise<string>((resolve) => {
            SendQueue.methodQueue.enqueue(async () => {
                const result = await Send.m3(param1, param2);
                resolve(result);
            });
        });
    }
}

最后我有Send类,它有实际的代码

class Send {
    public static async m1(param1: string, _param2: number): Promise<string> {
        console.log(`Done ${param1}: ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()}:${new Date().getMilliseconds()}`);
        return "result from m1";
    }

    public static async m2(param1: string): Promise<string> {
        console.log(`Done ${param1}: ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()}:${new Date().getMilliseconds()}`);
        return "result from m2";
    }

    public static async m3(param1: string, _param3: boolean): Promise<string> {
        console.log(`Done ${param1}: ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()}:${new Date().getMilliseconds()}`);
        return "result from m3";
    }
}

当我执行多个请求时,它的命中和未命中与调用之间的多个等待

(async () => {
    SendQueue.m1("m1", 1);
    SendQueue.m2("m2");
    SendQueue.m3("m3", true);
    await new Promise((resolve) => setTimeout(resolve, 1000));
    SendQueue.m1("m4", 1);
    await new Promise((resolve) => setTimeout(resolve, 2000));
    SendQueue.m2("m5");
    await new Promise((resolve) => setTimeout(resolve, 2500));
    SendQueue.m3("m6", true);
    await new Promise((resolve) => setTimeout(resolve, 1000));
    SendQueue.m1("m7", 1);
    SendQueue.m2("m8");
    SendQueue.m3("m9", true);
    await new Promise((resolve) => setTimeout(resolve, 13000));
    SendQueue.m1("m10", 1);
    await new Promise((resolve) => setTimeout(resolve, 1000));
    SendQueue.m2("m11");
    SendQueue.m3("m12", true);
    await new Promise((resolve) => setTimeout(resolve, 1000));
    SendQueue.m1("m13", 1);
})();

输出:

我的代码有什么问题?

k3bvogb1

k3bvogb11#

我看到了一些潜在的问题。
首先,在await method();周围没有try/catch。因此,如果该方法拒绝,您将永远不会将this.isExecuting = false;设置回false,并且您将不会调度队列中的下一个方法。
第二,执行setTimeout(),但如果在计时器触发之前,其他代码调用了enqueue(),那么它将在计时器触发之前调用executeNext(),然后计时器将触发并再次调用它。似乎executeNext()需要知道计时器何时已经在运行,并且在计时器触发之前不执行任何操作。
以下是针对这些问题的建议修复方法(注意,我不是TypeScript人员,因此您可能需要为新的timer示例变量分配类型):

class MethodQueue {
    private queue: (() => Promise<any>)[] = [];
    private isExecuting = false;
    private timer = null;

    async enqueue(method: () => Promise<any>): Promise<void> {
        this.queue.push(method);
        if (!this.isExecuting) {
            this.executeNext();
        }
    }
    private async executeNext(): Promise<void> {
        // don't run another method if we're already
        // running one or if one is scheduled to run
        if (this.isExecuting || this.timer) return;
        this.isExecuting = true;
        const method = this.queue.shift();
        if (method) {
            try {
                await method();
            } catch(e) {
                console.log(e);
            } finally {
                this.isExecuting = false;
            }
            this.timer = setTimeout(() => {
                this.executeNext();
                this.timer = null;
            }, 1000);
        } else {
            this.isExecuting = false;
        }
    }
}

相关问题