如何处理事件监听器和共享状态中的竞争条件?
How to deal with race conditions in event listeners and shared state?
我有 2 个事件侦听器在同一个共享 data/state 上运行。例如:
let sharedState = {
username: 'Bob',
isOnline: false,
};
emitter.on('friendStatus', (status) => {
sharedState.isOnline = status.isOnline;
});
emitter.on('friendData', (friend) => {
if (sharedState.isOnline) {
sharedState.username = friend.username;
}
});
我的问题是这些事件以任何顺序发出。 friendData
事件可能会在 friendStatus
之前发生。但是 friendData
对 friendStatus
返回的数据做了一些处理。换句话说:我需要 friendData 的事件处理程序在 afterfriendStatus 后执行,但从事件发射器的角度来看我没有这种保证。我需要以某种方式在我的代码中实现它。
现在我当然可以简单地从 friendData
侦听器中删除 if (sharedState.isOnline) {
并让它 运行 顺其自然。然后,在两个处理程序都完成并稍微协调共享状态依赖性之后,我将有一个函数 运行:
emitter.on('friendStatus', (status) => {
sharedState.isOnline = status.isOnline;
reconcileStateBetweenUsernameAndIsOnline();
});
emitter.on('friendData', (friend) => {
sharedState.username = friend.username;
reconcileStateBetweenUsernameAndIsOnline();
});
问题是这个协调函数知道这个特定的数据依赖用例;因此不能非常通用。对于大量相互关联的数据依赖,这似乎更难实现。例如,我已经在处理其他订阅和其他数据依赖项,而且我的协调功能变得非常庞大和复杂。
我的问题是:是否有更好的建模方法?例如,如果我能保证处理程序会按特定顺序 运行,我就不会遇到这个问题。
编辑:预期的行为是使用 sharedState 并呈现一个 UI 我希望用户名仅在状态 isOnline 为真时显示。
从@Bergi 在评论中的回答来看,我暗示的解决方案似乎最适合这种情况。只需让事件处理程序设置自己的独立状态,然后观察值的变化并根据您需要做的事情编写适当的逻辑。例如我需要显示用户名;这个函数不应该关心顺序或者知道时间:它应该简单地检查 isOnline
状态是否为真以及是否有用户名。然后,每当函数的每个依赖项发生变化时,可观察模式可用于调用此函数。在这种情况下,该函数取决于 status.isOnline
和 friend.username
,因此只要这些值发生变化,它就会观察并重新执行。
function showUsername() {
if (status.isOnline && friend.username != '') return true;
}
此函数必须 observe
它所依赖的属性(status.isOnline 和 friend.username)。您可以查看 RxJS 或其他库以更 "standard" 的方式实现此目的。
我有 2 个事件侦听器在同一个共享 data/state 上运行。例如:
let sharedState = {
username: 'Bob',
isOnline: false,
};
emitter.on('friendStatus', (status) => {
sharedState.isOnline = status.isOnline;
});
emitter.on('friendData', (friend) => {
if (sharedState.isOnline) {
sharedState.username = friend.username;
}
});
我的问题是这些事件以任何顺序发出。 friendData
事件可能会在 friendStatus
之前发生。但是 friendData
对 friendStatus
返回的数据做了一些处理。换句话说:我需要 friendData 的事件处理程序在 afterfriendStatus 后执行,但从事件发射器的角度来看我没有这种保证。我需要以某种方式在我的代码中实现它。
现在我当然可以简单地从 friendData
侦听器中删除 if (sharedState.isOnline) {
并让它 运行 顺其自然。然后,在两个处理程序都完成并稍微协调共享状态依赖性之后,我将有一个函数 运行:
emitter.on('friendStatus', (status) => {
sharedState.isOnline = status.isOnline;
reconcileStateBetweenUsernameAndIsOnline();
});
emitter.on('friendData', (friend) => {
sharedState.username = friend.username;
reconcileStateBetweenUsernameAndIsOnline();
});
问题是这个协调函数知道这个特定的数据依赖用例;因此不能非常通用。对于大量相互关联的数据依赖,这似乎更难实现。例如,我已经在处理其他订阅和其他数据依赖项,而且我的协调功能变得非常庞大和复杂。
我的问题是:是否有更好的建模方法?例如,如果我能保证处理程序会按特定顺序 运行,我就不会遇到这个问题。
编辑:预期的行为是使用 sharedState 并呈现一个 UI 我希望用户名仅在状态 isOnline 为真时显示。
从@Bergi 在评论中的回答来看,我暗示的解决方案似乎最适合这种情况。只需让事件处理程序设置自己的独立状态,然后观察值的变化并根据您需要做的事情编写适当的逻辑。例如我需要显示用户名;这个函数不应该关心顺序或者知道时间:它应该简单地检查 isOnline
状态是否为真以及是否有用户名。然后,每当函数的每个依赖项发生变化时,可观察模式可用于调用此函数。在这种情况下,该函数取决于 status.isOnline
和 friend.username
,因此只要这些值发生变化,它就会观察并重新执行。
function showUsername() {
if (status.isOnline && friend.username != '') return true;
}
此函数必须 observe
它所依赖的属性(status.isOnline 和 friend.username)。您可以查看 RxJS 或其他库以更 "standard" 的方式实现此目的。