【发布时间】: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属性同时观察username和isOnline并在它们更改时相应更改?类似于 MobX mobx.js.org/refguide/computed-decorator.html 中的计算属性 - 我想我的问题是如何在 vanilla JS 中实现这一点 -
请自行回答!
标签: javascript asynchronous event-handling race-condition event-listener