Sign up ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

I haven't been able to find the appropriate terminology to search for content on the web related to what I'm asking, so I'm hoping someone on here can at least point me in the right direction.

I'm a fairly senior JavaScript developer, but I have a secret -- I don't like event-driven programming (aside from user-triggered event binding I mean). Something about it has never sat well with me, it's the feeling of a "disconnect" in the logic flow.

In the simple example of some module invoking arbitrary numbers of views, an event-driven friend would create event listeners for elements those views could have and keep any reference to the parent module out of the view code.

I, on the other hand, would pass reference to the parent module in to the views so that I could directly trigger the module's methods.

I go for the second approach because I know exactly what is going to happen and what method I'm triggering at all points in the code. In the event-driven case I'm separating the assignment of an event response from the element that would trigger it, putting things in to the 'listening ether'.

I know responsible event-driven programming should avoid any risks like double-binding, etc., but even when that care is taken I still see it all as a bit of a black-box ripe for debugging nightmares. While passing references may be a bit more cumbersome in the code, at least it's clear what things are going to happen and when.

Can anyone identify the pros and cons of these two methods, and in particular why JS seems to be pushing in general toward the event-driven stuff?

share|improve this question
    
what is the question? – gnat Dec 16 '13 at 20:04
    
How do you respond to user interactions without events? – Robert Harvey Dec 16 '13 at 20:23
    
I said in my second paragraph -- user events aside. So the user clicks a button, but if that button needs to run a method in some other module, should that module be listening for the button or should the button have reference to the module scope to trigger the method directly? – Dan Dec 16 '13 at 20:26
5  
@Dan: 2 people have put in the effort of interpreting your question and we both have, IMO, provided a complete an answer as possible given the question. If you don't accept either one of them, then could you please explain why? Perhaps clarify the actual question some more, using code examples? – Elias Van Ootegem Dec 18 '13 at 8:23

2 Answers 2

Not sure what you mean with reference driven programming. From what I gather, you're wondering what the advantages of event-driven programming are as opposed to writing code, and then using a bunch of branches to determine when to call a given method.

Before I set off, allow me to be pedantic and point out that: a module can't listen for any event, nor can a button have a reference to a module. The button is part of the DOM, the module is JS. Both live in separate universes, and never the twain shall meet.
You can have the event loop pick up on certain events, and then invoke a given function object (either stand-alone, anonymous, or a function object that is part of a module) to handle that event, or you can mix JS into your markup, using certain html attributes (onclick="" and the like).
The latter method is generally said to be outdated, messy, and therefore bad practice. In this day and age, where OOP-buzzwords have found there way into the daily vocab of the average middle-manager, mixing JS in with markup isn't what I'd call separation of concern...

I see it like this:
JavaScript was originally intended to run client side. It's not been considered a valid server-side language for that long. It's small, light and portable, and was meant to make it easy to "liven up" your website. Making the UI responsive, move stuff around and, most importantly, load content dynamically using AJAX.
When talking about AJAX, I think you'll agree, event-driven programming is the better option: you request content, based on user input (clicks links, scrolls the page down etc...), and as you probably know: an ajax response is dealt with using an event handler (xhr.onreadystatechange = function).

Since then, we've come a long way, but some things have remained the same: JS is, in essence, a functional language, which implies closures, lambda's and callback functions to be used all over the place. The easiest way to make functional code work is to set all the functions up, and then let a change in the state (aka event) call one or more of these functions. Basically: functional languages feel at home in an event driven universe.
The expressive power of these constructs is huge, and so it stands to reason that with every new trick, technology or feature that gets added, the people developing the JS engines will tend to implement events to better support these new bells and whistles. Couple that to the fact that the main libs/toolkits will probably provide an API that requires you to pass around functions, and you end up with a bunch of developers who, when confronted with a problem, will look at it as a series of events, that they can tap into to respond accordingly.
So, I guess you might say that JS was designed to be event-driven to a rather large extent, and that the people who use it are "trained" if you will to think accordingly.

Another thing to consider is: how the engines work. V8, for example, is great at idling. If you run node.js, you'll see that it's perfectly happy, consuming very little resources, just sitting there, doing nothing. Once it receives a request (which is an event in a way), it'll wake up and set to work.
Event driven code does reflect this:

http.createServer(function(){}).listen();

This script doesn't do anything, until the server "has to be there", then the function passed to createServer is invoked, and, you could say, becomes the server.

Back to the client-side:
You say you see the point of event binding with DOM elements, and responding to the user's actions. Well, that's what client-side JS does. Its main purpouse was (and is) to augment the user experience. Whatever code gets executed client side, should be triggered by an event.
The event could be the load event, or a click or change event... it doesn't matter. If the user isn't doing anything, JS shouldn't be busy. Some browsers kill a script if it's busy for too long anyway.
You ought to realize that picking up on changes, without using the event loop JS already has to offer, leaves you no real alternative than to write a busy loop: JS isn't meant to be a system language, so you could end up with: for(;;) or while(1) loops. If you then were to have a single event handler, owing to JS being single threaded, that handler can't ever get called, because the JS thread is always busy, claiming the CPU like there's no tomorrow.

I can't see how else you could set about your business, to be honest. Worker's? No, because they communicate only through events. setTimout and setInterval? Not really: it's a right hasstle to sort out the scope, it's error prone and expensive. Besides, an event probably translates to an interrupt at some lower level, as does an interval, or a timeout. What those do is, essentially the same thing as events, only: they're obtrusive, because they weren't initiated by the user, and they could block the UI.
The only "alternative" I can think of, and reading your question and comments again is what you're actually thinking of, is something along the following lines. The first is the reference driven example, the second is a quick translation of the same basic concept to event-driven programming:

var btnMod = (function(w)
{
    var nextOn = false,
    stopEvent = function(e)
    {
        e.returnValue = false;
        e.cancelBubble = true;
        if (e.preventDefault)
        {
            e.preventDefault();
            e.stopPropagation();
        }
        return false;
    },
    module = {};
    module.switch = function(e,elem)
    {
        e = e || w.event;
        //do stuff
        nextOn = !nextOn;//toggle bool
    };
    module.next = function(e,elem)
    {
        e = e || w.event;
        //do stuff
        if (nextOn) location.href = 'next-url';//for example
        else return stopEvent(e);
    };
    return module;
}(window));

then either have markup like below, or bind the module methods to certain elements

<li onclick="module.switch(event, this)">on/off</li>
<li onclick="module.next(event,this)">next</li>

As opposed to doing something like

var btnMod = (function(w)
{
    var stopEvent = function(e)
    {
        e.returnValue = false;
        e.cancelBubble = true;
        if (e.preventDefault)
        {
            e.preventDefault();
            e.stopPropagation();
        }
        return false;
    },
    module = {};
    module.switch = function(e,elem)
    {
        e = e || w.event;
        w.removeEventListener('click', module.switch, false);
        w.addEventListener('click', module.next, false);
    };
    module.next = function(e,elem)
    {
        e = e || w.event;
        w.removeEventListener('click', module.next, false);//unbind to disable
        //do stuff
    };
    if (!nextOn) w.addEventListener('click', module.switch,false);
    else w.addEventListener('click', module.next, false);
}(window));

Well, quite apart from the fact that event-driven code is lighter (only one listener is bound at a time), and less error prone (if the module.next listener is bound, the switch listener isn't), it also doesn't require JS to mixed in with JS. Given some more effort, it can also be written a lot shorter than the snippets I've posted here, and it's not littered with tons of if's and else's. it uses functions, which is what you do in a functional language

Bottom line:
The advantages of event-driven JS are simple, IMO: JS was intended to be used on the web, client-side. It was meant to enhance the user experience by making static pages responsive, and fetching content on-the-fly. All through events. Coupled with the functional paradigm, that makes for a rather expressive little language. To use it in any other way means using it in a way it wasn't designed to be used (excel).

If you don't use a hammer to fasten a screw if you have a screwdriver lying right next to it.
Likewise: you don't work around events, if there is an event readily available.

In the end, though, what's in a name?. If ever you write a standalone program in C, using the GTK+ lib, you'll use "events", too. C# is popular nowadays, guess what, it wont take many tutorials before you see the word "event" crop up. You want to react on some changes in state or user input? That's what we happen to call an event. Lastly: as svidgen pointed out: JS engines already have an event system written out. Good programmers are lazy: they don't go and write their own systems, if they can find an existing one that allows them to do what they need to do. Sure, sometimes you may find the existing systems lacking in some respect, and curse the people making it for not seeing that there might be a need for whatever you happen to need at that time, but that's life.
Personally, I'd say: if you don't like event-driven programming, you don't really like JS(?)

share|improve this answer

Not 100% sure I know what you're asking. But, I get the sense you're at a point where event-driven programming doesn't feel "real" enough -- or like you're at the mercy of someone else's event system. Or like your application isn't really "doing" anything. Or like it's just a bunch of disparate methods that you're feeding another application.

So. Suppose a user-facing application creates and environment and waits for stuff to happen, which is what most applications do. There are two ways to receive those "happenings."

Periodically poll for evidence that something has happened.

Pros:

  • You can respond to happenings that aren't "events" in someone else's event-model.
  • The application is not interrupted when it's in the middle of something important. (Not generally relevant concern in JavaScript, because events are queued until the pipe is clear.)
  • The application retains more precise control over what's running; it has the flexibility to completely ignore input, only check for input every N cycles or seconds, etc.
  • It may give you a [mistaken] sense of satisfaction that you're writing more real, more thorough code. You're not relying on some silly, mysterious event system. You're doing all the work, dammit!

Cons:

  • Application is iteratively checking for event flags, often needlessly.
  • CPU usage is high and potentially running inefficiently due to frequent context switches, increasing likelihood of thrashing.
  • You likely end up writing and event-system and event-driven code anyway ...

E.g. ...

while (true) {
  var flags;
  if (flags = checkMouseFlags()) {
    doMouseInput(flags);
  }
  if (flags = checkKeyboardFlags()) {
    doKeyBoardInput(flags);
  }
}

function doMouseInput() {
  // stop lying to yourself. this is an event.
}

function doKeyboardInput() {
  // this is also an event.
}

... Alternatively:

Let the host invoke the code when something happens.

Pros:

  • It's an extension of what happens at lower levels. Unless you're building the hardware, you're ultimately writing event handlers: The CPU is sleeping. It's woken up when something happens. The CPU interrupts the OS to say, "hey, something happened." The OS determines that Chrome should receive the event. The OS invokes Chrome's event-handler. Chrome sets some flags and stuff and invokes your event handlers.
  • You're not needlessly hogging CPU cycles and introducing context switches.
  • No need to (re)write and event-system [under the mistaken notion that it's not an event-system].
  • More reflective of reality, easier to wrap your head around, and easier maintain (once you embrace the model) (Even though you probably don't stop background thinking when you're in a conversation, you also don't "poll" for input. Input from your ears interrupts your thought-process and your respondToStupidRemark handler is triggered.)

Cons:

  • Puts you at the mercy of someone else's event-system.
  • Small chance you'll have to do some perverse looking stuff or poll for "events" anyway to respond to things that aren't "events" in your host's event-system.
  • Weird sense that your application isn't doing anything ...
  • ... Or maybe a weird sense that it's not even an application; just a bunch of tangentially related event-handlers.

Notable: In other languages, and with the advent of worker processes in JavaScript, it's not an either-or paradigm. You can have a background process butchering the CPU and use the existing event-system to do as much or as little with each event as you like.

So, why is JavaScript event-driven?

Because it's reflective of the modeled reality, easy to think about, gentle on the CPU, and it simply extends the host environment to the script.

share|improve this answer
    
+1 for the stop lying to yourself, this is an event comment, and because your answer is, of course, correct – Elias Van Ootegem Dec 17 '13 at 16:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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