Understanding Javascript Events and Promises

Earlier today a friend of mine asked me to explain events in Javascript. I took a quick stab at it, but despite him being one of the smartest people I know, he claims I did a really shitty job and left him more confused than anything else. Challenge excepted, Dan.

Why We Need Events and Promises

To grasp what events and promises are, it's helpful to understand the problems they solve. So let's start there.

Events

Javascript was developed to allow Web developers to create dynamic and interactive websites. To do that, developers needed a way to say, "when this happens (the event), do that."

For example, consider a something fairly simple like form validation. The goal is to execute some code after the user clicks the submit button but before the form submission actually occurs (perhaps even preventing that from happening). So, we create some code to listen for the submission event and respond to it:

var validateForm = function() {
  // Validation code goes here

 // Return true if valid, return false if not
};

<form onsubmit="return validateForm();">
  <!-- form elements go here -->
</form>

The form element's "onsubmit" attribute is executed when the user submits the form but before the submission is actually performed. By returning false when the form does not validate, you're telling the browser to not submit the form as it normally would. Returning anything else tells the browser to carry on as planned.

So the basic idea is this: You want your code to execute when a particular event occurs, but you have no idea if/when the event will occur. So you tell the browser to "listen" for the event (in this case, when our form is submitted) and execute your "callback" when it does.

Promises

Promises take the idea of events a little bit further (and obscure them with a new name just to keep it interesting).

One of the primary purposes of employing Javascript is presenting a snappy and fluid user experience, but the Internet is not always snappy and is rarely fluid. (Just think about how annoying it would be if you had to reload Gmail every time you wanted to check for new messages). So to compensate for that fact, Javascript is asynchronous.

In other words, when you instruct the browser to do certain tasks, your code continues to execute beyond the request as if it were instantly handled. In reality, it's being completed in the background. But that poses a problem, what do you do if you need to know the outcome of the request to decide what you want to do?

Think about the Gmail example. We don't want everything to stop while we check the server for new messages, but we also need to make sure to do something if new messages do exist.

var checkmail = function() {

    // First we define a function to handle the response
    var parseResponse = function(eventObject, requestObject) {
        if (requestObject.response.messageCount > 0) 
            // Process the new msessages
        }
    };

    // Then we execute the request and pass a reference to our function
    var request = new jQuery.post('http://myserver.com');
    request.ajaxSuccess(parseResponse);
};

Okay, to be honest, I've simplified this a little bit, but the concepts are all there. Here is the basic idea: We define a request to execute and attach a listener to execute when the request is successfully completed (this is the promise---the request object is promising to execute our code when it's completed the request).

Building On the Basics

Okay, so we bind to events and contract with promises using anonymous functions (or other callables). When the event occurs or the promise is fulfilled, our function executes. That may not seam terribly powerful, but when you consider that scope is passed with the callable and that arguments can be passed to the callable, the real power is revealed:

  • When an anonymous function is bound to a DOM element's event, the function executes in the element's context (the this keyword references the element emitting the event.
  • Arguments can be used to pass information about the event when it occurs or the promise is fulfilled (e.g. the payload of an AJAX response, a status code, or a even another promise).

In Conclustion

So those are the basics, but things can get much more complicated. Still, if you keep all of this in mind, you should be able to grasp the more advanced concepts with out too much trouble.

Here are some more advanced implementations of events and promises:

  • external libraries (e.g. jQuery) offer normalized APIs for binding with and responding to window, document and element events
  • HTML websockets provide various promises that can be used to develop unique and awesome Web applications over custom (or at least non-HTTP) protocols
  • non-browser platforms (including operating systems such as Windows 8 and desktop applications like GNOME) provide advanced asynchronous APIs that make it easy to write fully fledged applications using javascript, HTML and CSS