I've stumbled upon a design problem in a Node.js class I've been coding.
我在编写的一个Node.js类中偶然发现了一个设计问题。
I need to perform X amount of tasks concurrently (using Promise.all
) but these tasks share a value from a class context (this.value
).
我需要并发执行X个任务(使用Promise.all),但这些任务共享一个来自类上下文的值(this.value)。
This value expires, but the only way to determine whether it was expired or not is to check for it inside one of the many async tasks, so this raises the problem:
此值将过期,但确定它是否已过期的唯一方法是在许多异步任务之一中检查它,因此会引发问题:
When this value expires I need to update it, but I can only call a method to update it (ex: this.refreshValue
) from inside the async tasks, causing a bunch of concurrently running tasks to call that method, while I need to call it only once as soon as the value is expired.
当这个值过期时,我需要更新它,但我只能从异步任务内部调用一个方法来更新它(例如:this.renhValue),这会导致许多并发运行的任务调用该方法,而我只需要在该值过期后立即调用它一次。
Basically, the first task that notices the value has expired should stop all other tasks, update this value somehow alone without other tasks interfering, and then resume itself and all other tasks.
基本上,第一个注意到该值已过期的任务应该停止所有其他任务,以某种方式单独更新该值,而不受其他任务的干扰,然后恢复自身和所有其他任务。
Here is an outline of the class (useless but to give a generic idea of the code)
下面是这个类的大纲(没有用,但给出了代码的一般概念)
class MyClass {
constructor() {
}
async refreshSharedValue() {...}
async doWork() {
Promise.all([...].map(x => {
... Do Stuff with this.sharedValue
if (this.sharedValue is expired) {
// Stop ALL tasks inside Promise.all, call this.refreshSharedValue only ONCE, resume all tasks inside Promise.all
}
}))
}
}
Tried to use event emitters and some Proxy logic on a global variable but I can't stop all tasks from executing the refresh logic at once.
I just can't think of a way to avoid this, probably I'll have to not use Promise.all
.
尝试在全局变量上使用事件发射器和一些代理逻辑,但我无法同时停止所有任务执行刷新逻辑。我只是想不出一种方法来避免这一点,可能我将不得不不使用Promise.all。
更多回答
优秀答案推荐
I guess there are many ways to achieve this. I would share the state between the promises. You can leverage the single thread node.js feature to change the status of the state just one time without creating inconsistencies and the other promises would just wait until the shared status have the value needed to continue, this is the example I did it:
我想有很多方法可以做到这一点。我会在承诺之间分享这一状态。您可以利用单线程node.js功能只更改状态一次,而不会产生不一致,而其他承诺只会等待共享状态具有继续所需的值,这是我所做的示例:
class CustomClass {
sharedValue;
tasks = [];
constructor() {
this.sharedValue = {
status: "NO-OK",
};
// Populate 10 tasks to the array
for (let i = 0; i < 10; i++) {
this.tasks.push(this.randomAsyncTask());
}
}
// Define a method to refresh the shared status asynchronously.
async refreshingStatus() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Call one time");
resolve("OK");
}, 3000);
});
}
// Create asynchronous tasks that depend on the shared status.
randomAsyncTask() {
return () => {
return new Promise((resolve) => {
setTimeout(async () => {
while (this.sharedValue.status !== "OK") {
if (this.sharedValue.status !== "REFRESHING") {
console.log("Refreshing status");
this.sharedValue.status = "REFRESHING";
this.sharedValue.status = await this.refreshingStatus();
}
await new Promise((r) => setTimeout(r, 2000));
}
console.log("Task completed");
resolve("OK");
}, 1000);
});
};
}
async run() {
Promise.all(this.tasks.map((task) => task())).then((results) => {
console.log("All tasks were completed");
});
}
}
const customClass = new CustomClass();
customClass.run();
更多回答
我是一名优秀的程序员,十分优秀!