This is async code written with ES6 generators (and a library like Co or Koa):
var item = yield get.db('id...');
item.key = yield get('http://...').body.value;
yield item.save();
console.log('done!');
You just yield your async functions out of a generator. Behind the scenes, the async function's callback calls next
on the generator, allowing your code to resume.
compare that to writing callbacks...
get('http://...', function(err, res) {
db.get('id...', function(err, item) {
item.key = res.body.value;
item.save(function(err, item) {
console.log('done!');
});
})
});
Hard to follow^
OR promises...
var value;
get('http://...')
.then(function(res) {
value = res.body.value;
return db.get('id...');
})
.then(function(item) {
item.key = value;
return item.save();
})
.then(function() {
console.log('done!');
});
Obnoxiously verbose with variables declared outside the flow^
Basically, you can write async code in a really intuitive sync way. Look at error handling with generator based async:
try {
var item = yield get.db('id...');
item.key = yield get('http://...').body.value;
yield item.save();
console.log('done!');
} catch (err) {
//handle error
}
...nice, very easy.
All this sync code happens inside a generator function:
co(function *() {
var item = yield get.db('id...');
item.key = yield get('http://...').body.value;
yield item.save();
console.log('done!');
});
If you're familiar with Express, you can use Koa. All middleware are generators in the Koa framework. So you can write all your middleware like that^.
Your Koa middleware can yield to to downstream middleware, before returning to complete.
app.use(function *(next) {
var item = yield get.db('id...');
item.key = yield get('http://...').body.value;
yield item.save();
yield next;
console.log('done!');
});
OK, cool. There's a little trick to forming your functions so they work with generators in Koa.
You can yield a promise:
yield Q.nfcall(get, 'http://...');
OR a thunk:
(a function that returns a function that accpet only a callback)
function getThunk(url) {
return function(cb) {
get(url, cb);
};
};
yield getThunk('http://...');
OR, awesome alert, you can curry any function ending with a node style (err, res) callback to turn it into a thunk.
var curriedGet = curry(get);
yield curriedGet('http://...');
pure awesome.