Async code without callbacks with CoffeeScript generators



Sometimes it’s very hard to understand code with a bunch of callbacks, even if it with promises. But in ES6 and in CoffeeScript 1.9 we got generators, so maybe we can avoid callbacks with them, and use something like tornado.gen?

And we can, let’s look at this little helper function:

gen = ( fn ) -> new Promise ( resolve , reject ) -> generator = fn () putInGenerator = ( method ) -> ( val ) -> try handlePromise generator [ method ]( val ) catch error reject error handlePromise = ({ value , done }) -> if done resolve value else if value and value . then value . then putInGenerator ( 'next' ), putInGenerator ( 'throw' ) else reject "Value isn't a promise!" handlePromise generator . next ()

With it code like:

$http . get ( '/users/' ). then ({ data }) -> doSomethingWithUsers data . users $http . get '/posts/' , ( err ) -> console . log "Can't receive users" , err . then ({ data }) -> doSomethingWithPosts data . posts , ( err ) -> console . log "Can't receive posts" , err

Can be transformed to something like:

gen -> try { data : usersData } = yield $http . get '/users/' catch err console . log "Can't receive users" , err return doSomethingWithUsers usersData . users try { data : postsData } = yield $http . get '/posts/' catch err console . log "Can't receive posts" , err return doSomethingWithPosts postsData . posts

Isn’t it cool? But more, result of gen is a promise, so we can write something like:

getUsers = ( url ) -> gen -> { data : { users }} = yield $http . get ( url ) users . map prepareUser getPosts = ( url ) -> gen -> { data : { posts }} = yield $http . get ( url ) posts . map preparePosts gen -> try users = yield getUsers '/users/' posts = yield getPosts '/posts/' catch err console . log "Something goes wrong" , err return doSomethingWithUsers users doSomethingWithPosts posts

So, what gen do: