如何处理事件监听器和共享状态中的竞争条件?

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 之前发生。但是 friendDatafriendStatus 返回的数据做了一些处理。换句话说:我需要 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.isOnlinefriend.username,因此只要这些值发生变化,它就会观察并重新执行。

function showUsername() {
  if (status.isOnline && friend.username != '') return true;
}

此函数必须 observe 它所依赖的属性(status.isOnline 和 friend.username)。您可以查看 RxJS 或其他库以更 "standard" 的方式实现此目的。