Tuesday, July 23, 2013

Promiz.js


Promiz.js is a promises/A+ compliant library (mostly), which aims to have both a small footprint and have great performance (< 1Kb (625 bytes minified + gzip)). I wont go over why javascript promises are amazing. Instead, I'm going to focus on what goes on behind the scenes and what it takes to create a promise library. But first, some benchmarks (see bench.js for source - server side):
Benchmarks are obviously just that 'benchmarks', and do not necessarily test real-world application usage. However, I feel that they are still quite important for a control flow library, which is why Promiz.js has been optimized for performance. There is however, one thing I should mention: Promiz.js will attempt to execute synchronously if possible. This technically breaks spec, however it allows us to get Async.js levels of performance (note: Async.js is not a promise library and doesn't look as clean).

Alright, lets look at the API that our library has to provide. Here is a basic common use case:

function testPromise(val) {
    // An example asyncronous promise function
    var deferred = Promiz.defer()
    setTimeout(function(){
        deferred.resolve(val)
    }, 0)
    return deferred
}
testPromise(22).then(function(twentyTwo){
    // This gets called when the async call finishes
    return 33
}).then(function success(thiryThree){
    // Values get passed down the chain.
    // values can also be promises
    return testPromise(99)

}, function error(err) {
    // If an error happens, it gets passed here
})

Now, while the usage is simple, the backend can get a little bit complicated and requires a good bit of javascript knowledge. Lets start with the most minimal possible setup.

First we're going to need a generator, that creates the `deferred` (promise) objects:

var Promiz = {
    // promise factory
    defer: function(){
      return new defer()
    }
}

Now, lets define our promise object. Remember, to be spec compatible, it must have a .then() method, and have a state. In order to be able to chain these calls, we're also going to need to keep track of what we need to call later. This will constitute our `stack` (functions that need to be resolved eventually).

function defer(){

    // State transitions from pending to either resolved or rejected
    this.state = 'pending'

    // The current stack of deferred calls that need to be made
    this.stack = []

    // The heart of the promise
    // adding a deferred call to our call stack
    this.then = function(fn, er){
      this.stack.push([fn, er])
      if (this.state !== 'pending') {

        // Consume the stack, running the the next function
        this.fire()
      }
      return this
    }
}

The .then() simply adds the functions it was called with (a success callback and an optional error callback) to the stack, and then checks to see if it should consume the stack. Note that we return `this` which is a reference to our deferred object. This lets us call .then() again, and add to the same deferred stack. Notice, our promise needs to come out of its pending state before we can start consuming the stack. Lets add two methods to our deferred object:

    // Resolved the promise to a value
    // Only affects the first time it is called
    this.resolve = function(val){
      if (this.state === 'pending'){
        this.state = 'resolved'
        this.fire(val)
      }
      return this
    }

    // Rejects the promise with a value
    // Only affects the first time it is called
    this.reject = function(val){
      if (this.state === 'pending'){
        this.state = 'rejected'
        this.fire(val)
      }
      return this
    }

Alright, so this resolve actually does two things. It checks to see if we've already been resolved (by checking our pending state) which is important to be spec compliant, and it fires off our resolved value to start consuming the stack. At this point, were almost done (!). We just need a function that actually consumes our current promise stack (the `this.fire()` - the most complicated function).

    // This is our main execution thread
    // Here is where we consume the stack of promises
    this.fire = function (val) {
      var self = this
      this.val = typeof val !== 'undefined' ? val : this.val

      // Iterate through the stack
      while(this.stack.length && this.state !== 'pending') {
        
        // Get the next stack item
        var entry = this.stack.shift()
        
        // if the entry has a function for the state we're in, call it
        var fn = this.state === 'rejected' ? entry[1] : entry[0]
        
        if(fn) {
          
          // wrap in a try/catch to get errors that might be thrown
          try {
            
            // call the deferred function
            this.val = fn.call(null, this.val)

            // If the value returned is a promise, resolve it
            if(this.val && typeof this.val.then === 'function') {
              
              // save our state
              var prevState = this.state

              // Halt stack execution until the promise resolves
              this.state = 'pending'

              // resolving
              this.val.then(function(v){

                // success callback
                self.resolve(v)
              }, function(err){

                // error callback

                // re-run the stack item if it has an error callback
                // but only if we weren't already in a rejected state
                if(prevState !== 'rejected' && entry[1]) {
                  self.stack.unshift(entry)
                }

                self.reject(err)
              })

            } else {
              this.state = 'resolved'
            }
          } catch (e) {

            // the function call failed, lets reject ourselves
            // and re-run the stack item in case it handles errors
            // but only if we didn't just do that
            // (eg. the error function of on the stack threw)
            this.val = e
            if(this.state !== 'rejected' && entry[1]) {
              this.stack.unshift(entry)
            }

            this.state = 'rejected'
          }
        }
      }
    }

And that's it!

Sunday, July 7, 2013

CharityVid - User Auth, Jasmine Testing, and Dust.js

This is the last (official) post in my CharityVid series. I'm going to try and cram 3 big topics into one post, so lets see how it goes.

User Authentication

We're going to be using passport.js and MongoDB to create and store users. Here is what the passport code will look like:
 var passport = require('passport'),  
   FacebookStrategy = require('passport-facebook').Strategy,  
   db = require('./db'),  
   settings = require('./settings'),  
   log = require('./log');  
 passport.use(new FacebookStrategy({  
   clientID: FACEBOOK_APP_ID,  
   clientSecret: FACEBOOK_APP_SECRET,  
   callbackURL: "//" + settings.DOMAIN + "/auth/facebook/callback"  
 }, function(accessToken, refreshToken, profile, done) {  
   db.getUser(profile.id, function(err, result){  
     if (err || !result) { //user does not exist, create  
       //default user object  
       var user = {  
         fbid: profile.id,  
         username: profile.username,  
         displayName: profile.displayName,  
         ...  
       }  
       log.info("creating new user: "+user.fbid, user)  
       db.addUser(user, function(err, result) {  
         if(err || !result){  
           log.warn("error adding user", err)  
           return done(err)  
         }  
         return done(null, user)  
       })  
     } else {  
       return done(null, result)  
     }  
   })  
 }))  
 passport.serializeUser(function(user, done) {  
   done(null, user)  
 })  
 passport.deserializeUser(function(obj, done) {  
   done(null, obj)  
 })  

and then we need to add it in as express middleware.
 app.configure(function() {  
   app.use(express.cookieParser(settings.SESSION_SECRET))  
   app.use(express.session({  
     secret: settings.SESSION_SECRET,  
     store: new MongoStore({  
       url: settings.MONGO_URL  
     })  
   })) //auth  
   app.use(passport.initialize())  
   app.use(passport.session()) //defaults  
 })  
 app.get('/auth/facebook/callback', auth.passport.authenticate('facebook', {  
   failureRedirect: '/'  
 }), function(req, res) {  
   res.redirect('/')  
 })  
 app.get('/logout', function(req, res) {  
   req.logout()  
   res.redirect('/')  
 })  
 app.get('/auth/facebook', auth.passport.authenticate('facebook'), function(req, res) { /* function will not be called.(redirected to Facebook for authentication)*/  
 })  

Well that was a piece of cake, onto testing!

Testing

There are many kinds of testing (http://en.wikipedia.org/wiki/Software_testing#Testing_levels), and its up to you to decide how much or how little of it you wan't to do. CharityVid uses Jasmine-node for its tests. We have a folder named 'tests', and inside are javascript files named '<part of code>.spec.js'. The .spec.js extension tells jasmine that these are tests to run. Here is what a test might look like with jasmine:
 describe("Util check", function() {  
   var belt = require('../util')    
    it("retrieves charity data", function(done) {
        belt.onDataReady(function() {
            belt.getCharity("americanredcross", function(err, charity) {
                expect(charity.name).toBeDefined()
                expect(charity.website).toBeDefined()
                ...
                done()
            })
        })
    })
 })  

And then to test it:
 jasmine-node tests  

And now finally, onto Dust.js

Dust.js

CharityVid uses Dust.js, which is a template engine, similar to Jade, the default template engine used by express.js. Dust has a some nice features, including pre-compiled client side templates that can also be used server side (pre-compiling reduces the initial load times). Using dust.js is as simple as setting the view engine:
 var cons = require('consolidate')  
 app.engine('dust', cons.dust) //dustjs template engine  
 app.configure(function() {  
   app.set('view engine', 'dust') //dust.js default  
 })  

The dust engine comes from the Consolidate.js library, which supports a ton of different engines.
Here is an example of what dust.js looks like:
 {>"base.dust"/}  
 {<css_extra}<link href="/css/profile.css" rel="stylesheet">{/css_extra}  
 {<title}CharityVid - {name}{/title}  
 {<meta_extra}  
 <meta property="og:title" content="{name} - CharityVid"/>  
 {/meta_extra}  
 {<js}<script src='/js/profile.js' async></script>{/js}  
 {<profile_nav}class="active"{/profile_nav}  
 {<container}  
 <h1>{name}</h1>  
 <div class="row-fluid">  
   <img alt='{name}' class='profile-picture' src='https://graph.facebook.com/{fbid}/picture?type=large' align="left">  
   <span id='userQuote'>{quote}</span>  
   {?isUser}  
       <a class='edit' id='editQuote' href='#'>edit</a>  
   {/isUser}  
   <input type='hidden' name='_csrf' id='csrfToken' value='{token}'>  
 </div>
 {/container}