Moshe's Blog

Tips and tricks learnt along the way.

Writing Async Javascript Code in Sync Format - Part 1

| Comments

Writing async code is hard when not done properly. However there are ways to make it a breeze. One of them is to use promises and not have to worry about code being async or not.

I was looking around at different things and came across koa and got inspired to try a similar idea.

The basic idea of Koa is that when you need some async functionality you yield an async thingy like a promise or something similar and then koa waits for it to resolve and then continues your program injecting the new value into the function.

Sounds complicated? Let’s try an example (all examples will only run in FF unless Chrome decides to support generators)

Let’s start with a simple generator.

As you can see the syntax is function *() {} and you need to instantiate a generator before you can use it. For more info on the basics of generators see MDN

A cool thing about generators is that you can inject a value back into the generator function like so:

You actually can’t inject something into the first .next() call, if you try you get this error: TypeError: attempt to send "a" to newborn generator

Using just these two concepts and the very basics about Promises, we can write something that:

  1. Runs a generator until control is given back
  2. If result if promise like, then resolve it and inject the resolved value back to the generator
  3. Rinse and repeat.

Let’s start to write just that. Here’s what out program will look like:

function *program() {
    var rand;
    rand = yield getRandAsync();
    console.log('first time around = ' + rand);
    rand = yield getRandAsync();
    console.log('second time around = ' + rand);
}

function getRandAsync() {
    return Promise.resolve(Math.random())
}

run(program());

Now all we need to do is write the run function:

function run(gen) {

    step();

    function step(value) {
        var result = gen.next(value);
        if (result.value instanceof Promise) {
            result.value.then(step);
        }
    }

}

Putting that all together:

Now a couple of nice thigs to have. Let’s assume that sometime in the future getRandAsync is changed to just return a value and not a promise, we should handle that:

function run(gen) {

    step();

    function step(value) {
        var result = gen.next(value);
        if (result.value instanceof Promise) {
            result.value.then(step);
        } else if (!result.done) {
            step(result.value);
        }
    }

}

Easy enough. Now how would we handle concurrent async functions? Well the Promise object has a method all which handles it nicely, we just need to utilize it (MDN ctrl+f Promise.all):

function run(gen) {

    step();

    function step(value) {
        var result = gen.next(value);
        if (result.value instanceof Promise) {
            result.value.then(step);
        } else if (result.value instanceof Array) {
            Promise.all(result.value).then(step);
        } else if (!result.done) {
            step(result.value);
        }
    }

}

Now we can yield an array of promises to run and Promise.all will handle them. The great thing about Promise.all is that it will handle an array of non promises just as well

putting that all together we get a very powerfull way to write javascript:

Gist

Comments