My Resume, in JSON, Markdown and HTML with Javascript Promises

 

As an exercise in programming and learning some new javascript features, I've written my resume as JSON. The JSON gets loaded and turned into Markdown via handlebars.js, which then gets converted into HTML by marked.js. The page also uses require.js for module loading and highlight.js for syntax highlighting of the code blocks. You can see all of the code that makes the page run on bitbucket.

One of the interesting features I learned while building this is the idea of Javascript "Promises".   Often, when dealing with the asynchronous nature of javascript you end up having to nest calls, much like I have to do when rendering the different sections of the resume.

At first, I was doing something like this with nested closures and callbacks that get the processed markdown as an incoming parameter.  As you can see, this isn't very readable and would get worse and worse as you add more and more sections of the resume to parse.

self.contact.toMarkdown(function(contactMarkdown){
  self.experience.toMarkdown(function(experienceMarkdown){
    self.skills.toMarkdown(function(skillsMarkdown){
      var markdown = contactMarkdown;
      markdown += experienceMarkdown;
      markdown += skillsMarkdown;

      // Put markdown on the page now and process it using marked

    }
  }
});

By using jQuery's "Deferred" functionality, each of my toMarkdown functions return an object known as a "promise". Basically my asynchronous code goes off into a queue inside the Deferred object, and posts it's results to it using a method called "resolve".  Here's what that looks like inside of one of the toMarkdown() functions.

Contact.prototype.toMarkdown = function(onComplete){
  var self = this;

  var promise = $.Deferred();

  // Build out the markdown with handlebars.js
  self.renderTemplate('contact',self.contact,function(markdown){
    promise.resolve(markdown);
  });
  return promise;
};

It creates a promise, and then immediately called "renderTemplate", which is an asynchronous function that goes off and makes an ajax call to get a Handlebars template and render the markdown. Of course, before that even gets to happen, this function ends and returns the "promise" to what called it.

Later on, I can call "done" on the promise object,  and pass it a callback and when the render is actually finished, I'll get the markdown passed to my callback. That would look something like this:

var contactPromise = self.contact.toMarkdown();

contactPromise.done(function(markdown){
  // do something with the markdown here
};

Of course, this is only one call. What happens when I want to do all of them? Aren't we in the same exact boat of nesting asynchronous callbacks? After all I need to combine all the output from all of the toMarkdown() functions.

Well, jQuery has a solution for that. It is the $.when function.

// Go fetch all the pieces
var contactPromise = self.contact.toMarkdown();
var skillsPromise = self.skills.toMarkdown();
var experiencePromise = self.experience.toMarkdown();

// When all of them are done
$.when(contactPromise, skillsPromise,experiencePromise).done(function(contactMarkdown, skillsMarkdown,experienceMarkdown) {
  // Append all the markdown together
  var markdown = contactMarkdown;
  markdown += experienceMarkdown;
  markdown += skillsMarkdown;

  // Now do something with the markdown
});

So now, I create the three calls to toMarkdown() right inline in a row, much like you do in synchronous programming.  However, I don't get back the markdown, I instead get back a promise object (a jQuery.Deferred in this case).

The $.when method takes promises as arguments and returns another promise.  I call .done on that promise and when it's finished, I get all three rendered markdowns passed to my callback function.

Then I can concatenate them together and I'm off to the races, and I have some code that is really easy to read (Assuming you know how promises work)

jQuery's Deferred object isn't the only way to do promises, but I was already using jQuery and it was convenient. There actually is a sort of a standard forming around javascript promises. If you are interested, you can read more about that at promisesjs.org.

Oh, and if you are looking to hire a javascript developer, don't forget to check out the resume itself here.