【问题标题】:JavaScript Promises and race conditionsJavaScript Promise 和竞争条件
【发布时间】:2014-11-23 05:07:43
【问题描述】:

我刚开始在 JavaScript 中使用 Promises,使用 Q library。我遇到了竞争状况,想知道解决它的最佳方法是什么。

问题是 Q 总是使用 process.nextTick() 调用回调(在 Promises/A+ 规范中也提到过),这意味着我可能会错过在承诺解决和时间之间的对象中的一些状态变化回调被调用。我的具体问题是我有一个传入连接并且缺少第一条消息。使用EventEmitter 分发消息。

代码看起来像这样。它使用palava-client(但问题应该是通用的)并且是用CoffeeScript编写的:

defer = q.defer()
session.on 'peer_joined', (peer) ->
  defer.resolve(peer)
return defer.promise

还有别的地方

peer_promise.then (peer) ->
  peer.on 'message', (msg) ->
    console.log "Message received:", msg

第一条消息有时会丢失,因为它们在 Promise 得到通知之前就发出了。仅使用 EventEmitter 和 Callbacks 不会出现此问题,因为回调总是会立即被调用,从而阻止 JavaScript 线程处理传入的消息。

以下代码永远不会错过消息:

session.on 'peer_joined', (peer) ->
  peer.on 'message', (msg) ->
    console.log "Message received:", msg

您认为我可以使用 Promise 解决问题的任何方法吗?我真的很想在我的抽象层中继续使用它们,以确保只接受一个对等点。有没有其他方法可以避免这种竞争条件?

【问题讨论】:

  • 尝试阅读 jQuery 文档中的“$.Callbacks、$.Deferred 和 Pub/Sub”部分。它可能会鼓励你朝着有用的方向前进,即使你最终没有使用 jQuery。

标签: javascript promise race-condition q


【解决方案1】:

作为一个经常提倡使用promise的人,我的建议是:

这里不要使用承诺

Promise 代表一次性事件。它们是对 values 的抽象,一个 promise 改变了它的状态,它不能再改变了。 Promise 以待处理开始,并将状态 once 更改为已完成或已拒绝。

您面临一个场景,您有很多用户,每个用户都加入并需要添加事件,用户可能会“离开”,您的场景根本没有描述相同的线性流承诺擅长。 Promise 对于特定场景很有用——它们并不适用于所有并发问题。在这里使用事件发射器是非常合适的。

您的案例(用户加入)并不真正代表已解决的代理操作。 “不漏消息”的代码确实更正确

如果你仍然选择在这里使用 Promise

你可以做一些事情:

  • 您可以使用 Q 的进度事件并在创建阶段添加进度处理程序。请注意,Kris(Q 的作者)已将进度称为中断,并将在下一版本的 Q 中删除。我建议不要这样做。
  • 您可以将 message 回调包装为仅在附加处理程序后触发 - 累积在创建处理程序时(在数组中)触发的项目,然后在添加消息处理程序时全部触发(在您解决,在.then 上延迟您返回。

【讨论】:

  • 该库支持多个用户,但我正在构建一个实际上只允许一个用户的应用程序。这就是为什么我首先使用 Promise。我只想处理第一个进入的用户。
猜你喜欢
  • 1970-01-01
  • 2010-11-27
  • 2010-09-25
  • 1970-01-01
  • 2023-03-23
  • 2016-01-06
  • 2014-02-23
  • 2020-07-12
  • 2021-10-22
相关资源
最近更新 更多