【问题标题】:How to deal with race conditions in event listeners and shared state?如何处理事件监听器和共享状态中的竞争条件?
【发布时间】:2020-04-13 21:07:45
【问题描述】:

我有 2 个事件侦听器,它们对相同的共享数据/状态进行操作。例如:

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 为 true 时才显示用户名。

【问题讨论】:

  • (F)RP 和 observables 在这里可以做很多事情,但不清楚您在这里期望什么确切的行为以及 sharedState 甚至用于什么,因此很难写出具体的答案。
  • "如果最新的friendStatus 发出的isOnline 的值等于true,我只能显示friendData 返回的用户名" - 如果@ 987654334@ 值是假的,那你想显示什么?总是"Bob"?或者您在离线之前收到的最后一个用户名?还是什么都没有?或者是其他东西?此外,还不清楚sharedState 何时以及通过什么代码实际显示,以及事件处理程序是否也需要触发该显示。
  • 顺便说一句,不,这不是竞争条件,这只是一个状态机,根据接收事件的顺序可能会或可能不会有不同的结果。
  • @Bergi 我编辑了一个更具体的要求。但是这个例子是故意设计的,用来展示我在竞争条件下遇到的问题。我认为你是对的,observables 可能会有所帮助;从这个意义上说,我认为您暗示showUsername 属性同时观察usernameisOnline 并在它们更改时相应更改?类似于 MobX mobx.js.org/refguide/computed-decorator.html 中的计算属性 - 我想我的问题是如何在 vanilla JS 中实现这一点
  • 请自行回答!

标签: javascript asynchronous event-handling race-condition event-listener


【解决方案1】:

根据@Bergi 在 cmets 中的回答,我暗示的解决方案似乎最适合这种情况。只需让事件处理程序设置自己的独立状态,然后观察值的变化并根据您的需要编写适当的逻辑。例如我需要显示一个用户名;此函数不应该关心订单或有任何时间知识:它应该简单地检查isOnline 状态是否为真以及是否有用户名。然后,每当函数的每个依赖项发生变化时,都可以使用可观察模式调用此函数。在这种情况下,函数依赖于status.isOnlinefriend.username,因此只要这些值发生变化,它就会观察并重新执行。

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

这个函数必须observe它所依赖的属性(status.isOnline 和friend.username)。您可以查看 RxJS 或其他库,以便以更“标准”的方式实现这一目标。

【讨论】:

    猜你喜欢
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 2018-04-15
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多