Skip to content

Instantly share code, notes, and snippets.

@spasiu
Last active May 2, 2021 20:55
Show Gist options
  • Save spasiu/5d0e6fd6b76f96384a04 to your computer and use it in GitHub Desktop.
Save spasiu/5d0e6fd6b76f96384a04 to your computer and use it in GitHub Desktop.
writing async javascript

No more bullshit async code

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.

getting started:

Co

Koa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment