Archives for posts with tag: JavaScript

Provider” is a JavaScript programming pattern that I’ve found myself using more and more of late.

A Provider is an asynchronous function that can be called to provide a particular resource, if there is a need for it.  The Atom functions .need() and .provide() exist for just this purpose.

var
  a = atom.create(),
  need = a.need,
  provide = a.provide,
  json2src = 'https://raw.github.com/douglascrockford/JSON-js/master/json2.js'
;

// If JSON is built-in or already loaded, use that.
// Else, load Crockford's.
provide('JSON', function (done) {
  if (typeof JSON !== 'undefined') {
    done(JSON);
  } else {
    loadScript(json2src, function () {
      done(JSON);
    });
  }
});

need('JSON', function (JSON) {
  // Safely call JSON functions in all browsers.
  console.log(JSON.stringify(document.location));
});

Providers in Atom are nice because:

  • They only get invoked if necessary — that is, if there is a need and if the property is not already set — so you benefit from lazy loading; and,
  • They get invoked at most once, even if multiple consumers call .need()
  • Resources are just Atom properties, so you can use them with other Atom functions, too.

More about Atom:

Advertisements

Any JavaScript library that claims to help with “asynchronous control flow” must at least enable easy patterns for running asynchronous tasks in parallel, or in series.

With Atom, task parallelization is easily accomplished using .set() and .once().  (Note that this is an application of the Barrier pattern.)

var
  a = atom.create(),
  once = a.once,
  set = a.set
;

ajaxCall('/me/friends', function (friends) {
  set('friends', friends);
});

ajaxCall('/me/games', function (games) {
  set('games', games);
});

once(['games', 'friends'], function (games, friends) {
  alert(games.length + ' games and ' + friends.length +
    ' friends were fetched in parallel.');
});

And task serialization is a cinch with .chain(). Each Atom instance has an asynchronous queue of functions. With each call to .chain() you can append one or more functions to the end of the queue.

a.chain(

  // First, fetch config info from the server
  function (next) {
    ajaxCall('/config', function (config) {
      // Signal that this task is done, and pass along the config
      next(config);
    });
  },

  // Second, build the UI
  function (next, config) {
    buildUI(config, function (ui) {
      next(config, ui);
    });
  },

  // Third, wait for user to select an option
  function (next, config, ui) {
    ui.on('select', function (choice) {
      switch (choice) {
      case 1:
        // ...
      }
    });
  },

  // ...
);

For more about Atom, see:

In May, I released a small JavaScript library called Atom.  Though only a couple of Kb minified, it is nonetheless very useful for a number of things, and my team at Zynga has been using it for almost all new projects we’ve started in the past few months.

In this post, I want to demonstrate a common and useful pattern that we use Atom for, which we call the Barrier pattern.

The essence of the Barrier pattern is that we have some code that we want to be run only after a certain set of conditions are met. To accomplish this, we need use only two Atom methods: .once() and .set().

var
  a = atom.create(),
  once = a.once,
  set = a.set
;

once(['cleanedRoom', 'brushedTeeth'], function () {
  sayGoodnight();
  goToBed();
});

In the example above, the two conditions are represented by the ‘cleanedRoom’ and ‘brushedTeeth’ properties of an atom instance. We don’t care which order they are completed in — only that they are both completed as a prerequisite to saying goodnight and going to bed.

The Atom method .once() lets us register a callback that gets called as soon as some combination of properties gets set, so it suits the purpose of the simple barrier above nicely.  However, we also have access to the value of the properties, which can be useful:

if (typeof jQuery !== 'undefined') {
  set('$', jQuery);
} else {
  loadScript('//code.jquery.com/jquery-1.8.3.min.js', function () {
    set('$', jQuery.noConflict());
  });
}

once('$', function ($) {
  $(function () {
    set('body', $(document.body));
  });
});

once(['body', '$'], function (body, $) {
  body.append('We have jQuery and can start manipulating the DOM!');
  // ...
});

This example is a robust usage of jQuery, that does not depend on jQuery already being loaded prior. If jQuery is not detected at the start, we make an asynchronous call to load it. Either way, as soon as we’re sure it exists, we set the ‘$’ property.

With Atom, when you use .set() to set a value for a property, it will trigger any listeners for that property immediately. So we have not only set up a barrier for code to wait for jQuery before executing, but we also provide a safe reference to it (on the highlighted lines).

I hope it’s easy to see how the barrier pattern as enabled by Atom can easily be used to make sure that your code gets run as soon as the necessary prerequisites are set, and not before. For more information about Atom, read the README.

I’m happy to announce that with the support of my employer, Zynga, I’ve just released an open-source component called Atom.

Atom is a small JavaScript class that provides asynchronous control flow, property listeners, barrier pattern, and more.  It is easy to include in any JS project, liberally licensed (BSD), cleanly coded and documented, and includes unit tests.  We’ve been using it internally for a handful of projects, and it is a good fundamental building block to help simplify complex application logic, especially in a highly asynchronous environment.

Check it out!