Adding promises to Twitter Flight

 Drafted in May 2013, but never quite finished, until now.

A good dose of Bootstrap is a wonderfully simple way to tart up your tired web site. So when Flight, an event based web framework, was open sourced early 2013 I was very interested to see what the talented engineers at Twitter had been up to.

Flight lets you construct your site with lightweight components. The key feature being that components cannot reference each other. All communication is via events delivered through the DOM.

As Zef Hemel asserts events are great, but often you really need a contract. He argues the answer is through dependency injection. By directly calling another object, you know immediately if the call succeeded or not.

Since Flight is built using AMD, this is still possible. I use AMD primarily as a dependency injection framework. When defining each module, you specify what other modules it depends on. As mentioned above, Flight components cannot refer to other flight components, so if you did use this approach with Flight, you’d need to move logic into classes that aren’t Flight components. This defeats the purpose.

pet peeve I have about Flight’s event implementation is they are triggered synchronously. If you’re expecting a response event back, this could come either synchronously or asynchronously. So your response handler may or may be called prior to execution of any code after your request event trigger.

Coordinating multiple asynchronous actions using events can also be challenging. You end up with in a maze of event handlers. Prior to Flight this was handily solved using promises – a concise robust means of coordinating multiple concurrent requests. Promises are always asynchronous, even if a promise is resolved, so you can be sure of the sequence in which your code is executed.

What if I could get the decoupled nature of Fiight with the power and conciseness of promises? Instead of sending request events, and praying you’ll get a matching response callback later, how about calling a function and getting a promise for the response in return.

Handily Flight comes with a decent mixin api for sharing common logic between components. I used this to create a promises mixin that lets you do just that.

To use, add the promise library Q and the promise mixin as dependencies on your Flight component, and pass the mixin as an argument to defineComponent.

define([
 'flight/lib/component',
 'Q',
 'mixin/promise'],

 function(defineComponent, Q, withPromises) {
 'use strict';

   function myComponent() {
     /*jshint validthis: true */

     ...

   }

   return defineComponent(myComponent, withPromises);
 }
);

To call a promise based command provided by another component use the call function.

  var myPromise = this.call({
    element: document,
    type: 'myCommand',
    data: { /* args to command */ }
});

To register a command that provides a promise use the registerCall function.

  this.myCommand = function(args) {
    // do stuff
    return newPromise;
  }

  this.after('initialize', function() {
    this.registerCall({
      element: document,
      type: 'myCommand',
      callback: this.myCommand
    });
  }

One caveat is you currently can’t use the mixin when Flight is in debug mode. The Flight engineers added a safety check in debug mode to prevent a component’s functionality being invoked by proxy from elsewhere. In this case, as long as you only return simple objects in your promise, we’re not breaking the encapsulation.