我正在寻找一种模式来解决一个典型的问题,当多个(用户)事件彼此紧接着又被触发时,每个事件必须照顾一些繁重的负载,这些负载必须在新事件发生之前进行处理可以接受。
例如,典型的用例是用户可以单击的项目列表,并且对于每个项目,都需要异步加载和处理。 用户将单击将触发异步处理的项目。 处理事件时,选择另一个项目时,不应再进行新的处理,并且在最佳情况下(性能),仅需要处理最后一个事件。
以下代码片段模拟了用例,控制台输出显示了事件是如何发出的,然后进行了处理。
函数run
模拟(用户)事件,函数heavyLifting
模拟异步繁重的工作。
处理了比所需数量更多的事件,并且通过确保仅使用heavyLifting
信号量依次调用currentlyLifting
函数,也不再保证至少始终处理最后一个事件。
使用JSFiddle来运行已截断的代码
const getRandom = (min, max) => Math.floor(Math.random() * (max - min) + min);
const heavyLifting = id => {
return new Promise(resolve => {
const cost = getRandom(500, 750)
console.log(`heavy lifting "${id}" with cost "${cost}" started...`);
setTimeout(() => {
console.log(`heavy lifting "${id}" completed.`);
resolve();
}, cost);
});
};
let currentlyLifting;
window.addEventListener('heavyLift', async (e) => {
const id = e.detail.id;
if (currentlyLifting !== undefined) {
console.log(`cannot start new heavy lifting of "${id}" while still running "${currentlyLifting}"`);
} else {
currentlyLifting = id;
await heavyLifting(id);
currentlyLifting = undefined;
}
});
const run = () => {
let id = 1;
const timerCallback = () => {
console.log(`dispatchEvent "${id}"`);
window.dispatchEvent(new CustomEvent('heavyLift', {detail: {id}}));
if (id++ < 10) {
setTimeout(timerCallback, 100);
}
};
timerCallback();
};
run();
<!DOCTYPE html>
<html>
<body>
<script src="index.js"></script>
</body>
</html>
答案 0 :(得分:0)
您可以在进行下一个处理之前等待上一个处理承诺:
const oneAtATime = () => {
let previous = Promise.resolve();
return action => previous = previous.then(action);
};
const lifting = oneAtATime();
lifting(async function() {
//...
});
lifting(async function() {
//...
});
或者等待刚刚完成的所有当前操作
await lifting(); // don't do that in a lifting task itself, that will cause a livelock