Managed event flow in qooxdoo

Introduction

The problem described below can be relevant for almost any event-driven JS infrastructure and any application that processes incoming data / event streams. For the sake of certainty, imagine web IM (Facebook chat) using the qooxdoo framework.

An application receives an incoming stream of events (for example, via WebSocket) and re-emits events into internal classes:

Events are processed, roughly speaking, in two stages. The handlers of the first stage are basically warnings (playing sound on an incoming message, displaying a web notification, etc.). The second stage is the actual processing and display of data. Both stages handlers are called simultaneously as events occur.

This model provides a good decoupling of the code between the application and the handlers, allowing you to add / remove and enable / disable them independently. But...

Problem

... as the application develops, it turns out that there may be dependencies between stages. Some stage 1 handlers must block operation in stage 2 (for example, an incoming voice recording should not start automatically until the sound notification is complete). Some may even show user confirmation and cancel the rest of the chain if no confirmation has been received. Event processing in qooxdoo assumes that all handlers are invoked (almost) at the same time, and there is no control over the order and time of the call of the handlers.

How do we introduce the required control, remaining within the framework of the event model and not sacrificing its advantages (low connection, etc.)?

Decision

The candidate’s decision uses Promises . By default, qooxdoo event handlers return nothing. Why not make them (optional) return a promise? In this case, an event mediator should be presented:

Now the handlers should be subscribed to the intermediary (for clarity, this is omitted from the diagram). The mediator, in addition to the standard on / off methods, must implement the after method with the following semantics:

  • after(String name, Function listener, var ctx?) - call the handler after all other handlers for this event
  • after(String name, Integer id, Function listener, var ctx?) - call the handler after another handler with a known identifier
  • after(String name, (Class|String) id, Function listener, var ctx?) - call the handler after all other handlers of some well-known class (can be obtained from the this argument of the corresponding call)

Thus, we extend the existing event semantics at two points:

  • event handlers can now return Promises;
  • The after method is introduced for the emitter / mediator of the event.

The emitter / mediator should allow dependencies and calls of wire handlers to the corresponding then() Promises blocks.

The proposed solution seems to satisfy both requirements: 1) it implements dependencies between event handlers, 2) it allows you to stay within the framework of the event processing paradigm. Are there any pitfalls? Can it be done better / cleaner? Any criticism and advice are welcome.

+5
source share

Source: https://habr.com/ru/post/1242097/


All Articles