8

Should an event listener be called if it is attached after the event has already fired? What if the event will only be fired once?

The first example that comes to mind is the ready event in jQuery. The following snippet, when evaluated after the page has loaded, will still call the callback:

$(document).ready(function () {
    console.log("Works.");
});

The alternative to this behaviour could be a flag that is set when the page is loaded, forcing the consumer of the API to check to see if the event has already happened and act accordingly:

if (document.readyState == "complete") {
    console.log("Works.");
} else {
    $(document).ready(function () {
        console.log("Works.");
    });
}

While the above example is in the context of a web page loading where anything and everything (usually) needs to happen after the page has completely loaded, the same arguments could be made for any single component in an application, which has "singleton" events (load, start, end, etc). An example of a single component could be a map with a load event that fires to specify that the map that has loaded:

map.on("load", function () {
    console.log("The map has loaded.");
});

The above example comes from the ArcGIS API for JavaScript, where that event is fired only once, and if an a consumer "waits" for the map to load after the map is already loaded, the listener will never be called. The desired result requires checking the state of the map before the listener is attached:

if (map.loaded) {
    console.log("The map has loaded.");
} else {
    map.on("load", function () {
        console.log("The map has loaded.");
    });
}

Which behaviour is correct, requiring the consumer to check if an event has already fired or always calling the callback?

  • 5
    You might be interested in Reactive Extensions' Subject vs. ReplaySubject, where the latter replays previous events for late subscribers whereas the former does not. That is, the creators of Rx modelled both behaviours instead of deciding on one definite behaviour. - And while the above links go to the documentation of Rx' .NET version, there's also a Rx for JavaScript. – stakx Nov 29 '14 at 16:56
19
+50

That depends upon whether it is really an Event or State Notification (which is what ready is). If it is an event, then you don't tell the listener about all prior events. If it is State Notification, then you tell them immediately after they have subscribed and you are in the specified state.

The tricky bit will be where it can be either a state or an event, depending upon how you look at it -- at worst, that is explained by the documentaion. At best you pick a good name that makes it clear which you mean.

  • 2
    +1, also for mentioning state notifications. State notifications are IMO close to futures and their handling of callbacks, e.g. in Scala (docs.scala-lang.org/overviews/core/futures.html). – Giorgio Nov 29 '14 at 17:19
  • Interesting, I hadn't thought of it like that. Would you classify load, start, or end the same as ready, as a state notification? – Whymarrh Nov 29 '14 at 17:23
  • @Whymarrh: That will depend upon context, but these sound like events to me. I would tend to name state notification as questions...ready? started? running? but of course you may have to fit it into an existing naming convention. – jmoreno Nov 29 '14 at 20:48
  • 3
    Seems to me like events can be interpreted as something that occurs once to change the state. This means they are very shortlived, practically a single moment. A state on the other hand is longerlived and consists of multiple moments. load isn't an event nor a state. loadingStarted is an event and loading is a state. – Jeroen Vannevel Dec 4 '14 at 0:39
5

In general, no.

Event listeners should not be called if they are attached after the event has already fired. "You snooze, you lose."

There are some important exceptions. $(document).ready() is perhaps the perfect example--a event prior to which the entire evaluation context is not reliably or completely established, and which serves as a "full function processing begins here" marker.

If however you set the rule that an event handler should be fired even if it is installed and/or activated after the event occurs, then you have declared that all events should or must be buffered from the beginning to the end of the program run, for every conceivable event. Else, there might be event handlers established on some event, somewhere down the road, that you don't have sufficient information to know if you should fire when it's established. That means you'd have to instrument every possible event source and infinitely buffer every one of them too. That takes event processing from lazy evaluation (and all of its performance benefits) all the way through eager evaluation and onto whatever is on the far end of the spectrum. Frenetic evaluation based on catastrophized assumptions about what events might need to be handled later?

Events tend to be transient and numerous. Setting rules that require each be buffered, without limitation, on the possibility that they'll eventually be tapped--it's performance suicide. Furthermore, there's no great requirement for doing so, since handlers can generally be established early in program life.

The exceptions to the rule are edge cases--document or subsystem loads, for example, that are essential, unique, major events that are not otherwise captureable or handleable. This is very close to your "singleton" events. Another group that might need special handling are significant errors, security events, or status changes that have an exceptional need to be flagged even if there are no subscribers to the flag at the moment the event occurred.

One final note: A "ready" event is subtly different from a "load" event. While they're often not clearly distinguished (e.g. HTML's onload and jQuery's $(document).ready() considered logically very similar), and both signaling the availability of a resource or processing environment--but they're not quite the same. Loading (or the finishing of it) is a true event--something signaled from infrastructure to consumer. Readiness, however, is more the rendezvous of the infrastructure's loading the resource/environment and the consumer's getting around to being ready to consume/take advantage of that availability. Readiness comes after the load, and is one of those designated special events/coordination points that must be treated as queueable because you can't capture it any other way. That there are a few very special cases, however, doesn't mean that every event should be fireable a posteriori.

  • Erm, did you mean html's "onload"? – StarWeaver Dec 3 '14 at 23:38
  • @StarWeaver Thanks. Not sure if I slipped or my over-ambitious autocorrect did, but you're entirely right. Fixed. – Jonathan Eunice Dec 3 '14 at 23:42
  • NP, i'm not all up with html post 4 but it sounded odd. Nice explination, too. – StarWeaver Dec 3 '14 at 23:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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