我在我一直在编码的节点类中偶然发现了一个设计问题。
我需要同时执行 X 数量的任务(使用 Promise.all),但这些任务共享类上下文中的值 (this.value)。
这个值会过期,但是确定它是否过期的唯一方法是在许多异步任务之一中检查它,因此这就引发了问题:
当这个值过期时,我需要更新它,但我只能从异步任务内部调用一个方法来更新它(例如:this.refreshValue),导致一堆并发运行的任务调用该方法,而我需要值过期后仅调用一次。
基本上,第一个注意到该值已过期的任务应该停止所有其他任务,以某种方式单独更新该值,而不会受到其他任务的干扰,然后恢复自身和所有其他任务。
这是该类的概要(无用,但给出了代码的一般概念)
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
}
}))
}
}
尝试在全局变量上使用事件发射器和一些代理逻辑,但我无法立即阻止所有任务执行刷新逻辑。 我只是想不出一种方法来避免这种情况,可能我不得不不使用 Promise.all。
我想有很多方法可以实现这一目标。我会分享承诺之间的状态。您可以利用单线程 Node.js 一次更改状态的状态,其他 Promise 只会等待共享状态具有继续所需的值,这是我所做的示例:
class CustomClass{
sharedValue;
tasks = [];
async refreshingStatus(){
return new Promise((resolve) => {
setTimeout(() => {
console.log('Call one time')
this.sharedValue.status = 'OK';
resolve('OK');
}, 3000);
});
}
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);
});
}
}
constructor(){
this.sharedValue = {
status: 'NO-OK',
}
// Populate 10 tasks to the array
for(let i = 0; i < 10; i++){
this.tasks.push(this.randomAsyncTask());
}
}
async run(){
Promise.all(this.tasks.map(task => task())).then((results) => {
console.log('All tasks were completed');
});
}
}
const customClass = new CustomClass();
customClass.run();