Skip to content

Instantly share code, notes, and snippets.

@kavinyao
Created May 17, 2013 10:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kavinyao/5598266 to your computer and use it in GitHub Desktop.
Save kavinyao/5598266 to your computer and use it in GitHub Desktop.
Practice code to help understand promise.
# Demo code in coffeescript for Callbacks are imperative, promises are functional: Node’s biggest missed opportunity
# http://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity/
# the original version uses rsvp.Promise
# since I'm a control freak, I'd prefer Deferred
Deferred = require 'deferred'
slice = Array.prototype.slice
# transform a callback-based function to return a promise
# fn == function(param..., function(error, data...))
promisify = (fn, receiver) ->
# a wrapper function of compatible interface is returned
return () ->
# omit callback even if it's passed
args = slice.call arguments, 0, fn.length-1
dfd = new Deferred()
# use this callback instead
args.push () ->
results = slice.call arguments
error = results.shift()
if error
dfd.reject error
else
dfd.resolve.apply dfd, results
# do the real job
fn.apply receiver, args
return dfd.promise
# transform a list of promises to a promise of list
# the returned promise is like an array, you can access individual promises by indexing it
list = (promises) ->
list_dfd = new Deferred()
list_promise = list_dfd.promise
# this is not idiomatic, but this is just a piece of demo code, so...
list_promise[i] = p for p, i in promises
# "waits" for all promises to get resolved with a counter
results = []
done = 0
promises.forEach (promise, i) ->
promise.then () ->
# the original version does not handle multiple arguments, but here we do
result = slice.call arguments
# accumulate result
results[i] = result
if ++done == promises.length
list_dfd.resolve results
, (error) ->
list_dfd.reject error
if promises.length == 0
list_dfd.resolve results
return list_promise
# test promisify
fs = require 'fs'
fs_stat = promisify fs.stat
# we do not handle error, so make sure the both files exist
paths = ['file1', 'file2']
# cannot chain .forEach after .map as .forEach returns undefined
(stat_promises = paths.map fs_stat)
.forEach (promise) ->
promise.then (stat) ->
console.log stat
stat_promises[0].then (stat) ->
console.log 'this file size is', stat.size
# test list
stat_promises2 = list paths.map fs_stat
stat_promises2[0].then (stat) ->
console.log 'this file size is', stat.size
stat_promises2.then (stats) ->
console.log 'number of stats', stats.length
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment