Wednesday, January 30, 2013

Still not convinced about coffeescript?

Here is another example why you should start writing Coffeescript. The business story in this example is rather simple - I need to load all document from a collection (named Accounts), perform an asynchronous operation (notifyOwner) on each of them, and save all of them back to DB after all notifyOwner operations finish successfully. The following methods are available to achieve this simple task:
Account.find() #find all accounts
account.notifyOwner() 
account.save()
All three methods are asynchronous and return a jQuery promise which resolve with either the results or itself for chaining. Because there are multiple accounts involved, we will also need to take advantage of jQuery.when.

Here is how we implement the business logic in Coffeescript

Account.find()
  .then (accounts)->
     $.when (account.notifyOwner() for account in accounts)...
  .then (accounts...)->
     $.when (account.save() for account in accounts)...
  .done ->
     console.log 'successfully notified all owners'
It takes advantage of coffeescript's splats feature to overcome jQuery.when's inability to take in an array of deferred.
  #resolves only when all three deferred resolve) 
  jQuery.when(deferred1, deferred2. deferred3) 
  
  #immediately resolves with the array passed in) 
  jQuery.when([deferred1, deferred2. deferred3]) 
What Javascript does that Coffeescript translate to?
Account.find().then(function(accounts) {
  var account;
  return $.when.apply($, (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = accounts.length; _i < _len; _i++) {
      account = accounts[_i];
      _results.push(account.notifyOwner());
    }
    return _results;
  })());
}).then(function() {
  var account, accounts;
  accounts = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
  return $.when.apply($, (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = accounts.length; _i < _len; _i++) {
      account = accounts[_i];
      _results.push(account.save());
    }
    return _results;
  })());
}).done(function() {
  return console.log('successfully notified all owners');
});
If you don't mind a bit help from underscore, We probably can simplify the iteration logic:
Account.find().then(function(accounts) {
  var account;
  return $.when.apply($, (function() {
    return _(accounts).map(function(account){
      return account.notifyOwner();
    });
  })());
}).then(function() {
  var accounts = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
  return $.when.apply($, (function() {
    return _(accounts).map(function(account){
      return account.save();
    });
  })());
}).done(function() {
  return console.log('successfully notified all owners');
});
So, that's clearly a lot more key strokes than Coffeescript but that's not the point. The point is how easy to read this Javascript version vs the Coffeescript version. Code could be written only once but it often times has to be read multiple times afterwards. Which version will you rather read?

Now, are you convinced?

17 comments:

  1. Great writeup!

    I am using coffeescript but didn't know the trick you showed here. Now I'm applying it to my code but still has some boilerplate code I hate to write. It is because jQuery.getJSON returns an array. I have below code

    someHandler = (responses...) -> console.log(responses)

    urls = ['a.json', 'b.json']

    $.when(($.map(urls, (url) -> $.getJSON(url))...).then(someHandler)

    I expect 'responses' passed to someHandler is always an array of responses even when there is only one urls. However, because getJSON returns an array like [data, 'success']. The 'responses...' is no good. I'm using a workaround

    someHandler = (responses...) -> responses = if responses[1] instanceof Array then responses else [responses]

    Have you had this problem? Any suggestions?

    Thank you.
    Guoliang Cao

    ReplyDelete
  2. Guoliang,

    Try use underscore map instead of $.map which might flatten the resulting array unnecessarily for you. Underscore map always return an array.
    Let me know it worked for you.

    Kai

    ReplyDelete
  3. change control system I am impressed. I don't think Ive met anyone who knows as much about this subject as you do. You are truly well informed and very intelligent. You wrote something that people could understand and made the subject intriguing for everyone. Really, great blog you have got here.

    ReplyDelete
  4. FESHOP REDDIT Fe-acc18 TOR LINK FESHOP-CARD.RU I think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article.

    ReplyDelete
  5. Uniccshop sign up free loaded cracked accounts activated I have read all the comments and suggestions posted by the visitors for this article are very fine,We will wait for your next article so only.Thanks!

    ReplyDelete
  6. Uniccshop sign up free loaded cracked accounts activated I admire this article for the well-researched content and excellent wording. I got so involved in this material that I couldn’t stop reading. I am impressed with your work and skill. Thank you so much.

    ReplyDelete
  7. Nice to be visiting your blog once more, has been months for me. Well this article that I've been waited for therefore long. i want this article to finish my assignment within the faculty, and it has same topic together with your article. Thanks, nice share.
    Best Fullz Store High Valid And Refundable Time Trusted

    ReplyDelete
  8. Nice to be visiting your blog once more, has been months for me. Well this article that I've been waited for therefore long. i want this article to finish my assignment within the faculty, and it has same topic together with your article. Thanks, nice share.
    FESHOP-JET2.RU LOGIN DOMAIN 2020

    ReplyDelete
  9. A very awesome blog post. We are really grateful for your blog post. You will find a lot of approaches after visiting your post. Fleet manager

    ReplyDelete
  10. us import data I am impressed. I don't think Ive met anyone who knows as much about this subject as you do. You are truly well informed and very intelligent. You wrote something that people could understand and made the subject intriguing for everyone. Really, great blog you have got here.

    ReplyDelete
  11. I exploit solely premium quality products -- you will observe these individuals on: sherlock email extractor 1.1

    ReplyDelete
  12. Thank you a bunch for this with all of us you actually realize what you are talking about! Bookmarked. Please also seek advice from my site =). We could have a hyperlink change contract between us! importers data

    ReplyDelete
  13. There you can download for free, see the first of these data. this site

    ReplyDelete
  14. Very informative post! There is a lot of information here that can help any business get started with a successful social networking campaign. nova versão do HappyMod APC disponível

    ReplyDelete
  15. There you can download for free, see the first of these data. CBT Mass Email Sender

    ReplyDelete
  16. Awesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better! Cheers, keep doing awesome! office mac 2021

    ReplyDelete
  17. When your website or blog goes live for the first time, it is exciting. That is until you realize no one but you and your. office programm

    ReplyDelete