5

I'm fully aware that Promises and eventing are both ways to do asynchronous programming, and you can choose either one for a given project. However, in practice, the code base I'm working with is large and we use many 3rd party libraries that handles asynchronicity differently so mixing the two approaches together are unavoidable (and often with disastrous effect).

Too many times I've seen people fire an event and then do more stuff after it, while expecting the event handlers to have fully finished. Unfortunately some event handlers will start a chain of Promises but there is no way for the event source to know when that chain is resolved.

In theory, the proper way to do async programming with pure eventing alone would have been for the event handler to raise an "event_x_completed" event but that assumes that there is always exactly one event handler for the original "event_x" (unless you want the code to get ugly. See example at the bottom). In UI programming, we often should not care how many listeners there are. E.g. one user action could raise an event to trigger any number of UI components to refresh themselves.

Also, depending how it is done, it could create a tight coupling between the event source and the event listeners, which invalidates a big strength to use event in the first place. My project has a complicated UI so an event source can't/shouldn't care how many handlers are listening to an event.

I think it would be great to have an eventing system that tests whether each handler returns a Promise (or then-able object), and fire("event_x") should return Promise.all(all_promises_from_handlers) to the event source.

I've looked around (maybe not hard enough) and I don't see anyone talking about a Promise-aware eventing system. Do people have the same problem and how is it handled?

Edit for concrete example:

The originator of "SAVE_PRESSED" doesn't care how many handlers there are, it only cares that they are all completed. I think it would be immensely useful to be able to do this:

function saveClicked() {
    saveButton.disable();
    EventManager.raise("SAVE_PRESSED").then(function() {
        saveButton.enable();
    });
}

With pure event, of course we could loop through all the listeners and do this instead:

function saveClicked() {
    saveButton.disable();
    var listeners = EventManager.getListeners("SAVE_PRESSED"); // array
    EventManager.raise("SAVE_PRESSED");
    EventManager.listen("SAVE_COMPLETED", function(listener_id) {
        var index = listeners.indexOf(listener_id);
        listeners = listeners.splice(index, 1);
        if (listeners.length === 0) {
            saveButton.enable();
            // AND -- unregister this function as a handler for SAVE_COMPLETED
        }
    });
}

What I don't like about this:

  • The code is longer and it's not even complete and doesn't have proper error handling.
  • This depends on the listeners raising a "*_COMPLETED" event.
    • If this is not always true or required, then each listener needs to indicate whether they are async (will raise a COMPLETED event) or not. This is additional configuration to maintain.
    • And instead of EventManager.getListeners("SAVE_PRESSED"), we call EventManager.getAsyncListeners("SAVE_PRESSED");
  • This code / functionality should be provided by the EventManager
    • If it is moved into the EventManager, then "*_COMPLETED" events are essentially very special.

In a promise-aware event system, the handlers can tell the system that they are async by simply returning a then-able object.

0

2 Answers 2

1

A promise aware eventing system can help you build graceful solutions to complex problems. However, I think it is worth choosing an existing framework rather than creating your own.

The (JavaScript) framework I have used most is Dojo and it has a robust collection of event handling code.

It includes chaining events as mentioned, then, when and all. all is nice because it will wait for a set of promises to resolve before proceeding.

I suggest you run through some of the tutorials at their site to see if it will serve your needs well.

1
  • Thanks for the reply. We already have an event framework and we also use SAP UI5 so we rarely access the DOM elements directly to add events to it, so I'm not sure of Dojo is suitable. However it is good to know that someone else thinks A promise aware eventing system can help you build graceful solutions to complex problems. I was hoping for more responses to gauge general consensus but perhaps the community doesn't care that much about this topic.
    – RonJRH
    Commented Nov 28, 2016 at 19:59
0

In theory, the proper way to do async programming with pure eventing alone would have been for the event handler to raise an "event_x_completed" event but that assumes that there is always exactly one event handler for the original "event_x". In UI programming, we can't make that assumption. E.g. one user action could raise an event to trigger any number of UI components to refresh themselves.

Er no. You absolutely do not need to assume that there is always exactly one event handler.

There are exactly as many event handlers as you want there to be. An event handler registers itself in a list of handlers of that event.

event_x_completed(x_id) tells me exactly which event has completed. Not simply that it a type x event but it was exactly the x that I was waiting for.

It's confusing to mix two different paradigms but be sure you know to use both before you assume they are completely incompatible.

7
  • I guess I wasn't clear in my example. Let me use another one.
    – RonJRH
    Commented Nov 21, 2016 at 19:08
  • Theoretically you are right. It will however make the code much uglier (see my example next). Is that generally deemed acceptable over a promise-aware event system? That was my original question.
    – RonJRH
    Commented Nov 21, 2016 at 19:25
  • Let's say I have a save button that raises a "save_pressed" event. Let's say there are 4 listeners:<br/> 1. Save some state to backend system X<br/> 2. Save some state to backend system Y<br/> 3. Update the visual on UI component A( e.g. remove the "dirty" look)<br/> 4. Update the visual on UI component B (e.g. remove the "dirty" look)<br/> And I want to disable the button and re-enable it only after all of the above are done. When the button is re-enabled, user knows that the save operation is fully completed.
    – RonJRH
    Commented Nov 21, 2016 at 19:25
  • Even if 1, 2, 3, 4 each raises additional events e.g. save_completed(handler_id), The handler for "save_completed" is responsible for re-enabling that save button. And that handler needs to use maintain additional static state to know that it has seen all 4 handler_ids.
    – RonJRH
    Commented Nov 21, 2016 at 19:25
  • @user1754644 when I hear "event" I think observer pattern. When I hear the second half of your plan I think interrupts, just inverted. An interrupt register has all it's bits checked every CPU cycle. If any are high it's time to process all the interrupts and clear them. You want to do the same except rather than waiting for any you're waiting for all. Rather then a register you can have a collection of observers waiting for completion. Things get tricky if you ever let them reset. You don't want one click confused with another. There is also a loop here but it goes through the human. Commented Nov 21, 2016 at 20:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.