2015-11-03

Synchronous and asynchronous sequential execution of functions

This blog post examines three ways of executing function sequentially:

  • Synchronously
  • Asynchronously, via Promises
  • Asynchronously, via the library co

Synchronously

Synchronous sequential execution is built into JavaScript and looks like this:

    function func() {
        foo();
        bar();
        baz();
    }

Asynchronously, via Promises

To execute Promise-based functions sequentially, you need to chain function calls via then(), which is the Promise equivalent of the semicolon:

    /**
     * Returns a Promise that resolves to `undefined`.
     */
    function func() {
        return foo()
        .then(() => bar())
        .then(() => baz());
    }

If you are OK with executing the functions in an arbitrary order (the single-threaded version of “in parallel”), you can use Promise.all():

    /**
     * Returns a Promise that resolves to
     * [undefined, undefined, undefined].
     */
    function func() {
        return Promise.all([foo(), bar(), baz()]);
    }

Asynchronously, via the library co

The library co also works with Promise based functions. Its helper method, co.wrap(), converts a generator function gen into a function that returns a promisification of whatever gen returns. The neat thing is that gen can yield a Promise (e.g. the result of a function call) and is suspended while the Promise is pending. If the Promise is fulfilled, the fulfillment value becomes the result of yield. If the Promise is rejected, the rejection value is thrown as an exception.

Let’s look at an example:

    /**
     * The callback implicitly returns `undefined`.
     * Therefore, `func` returns a Promise that resolves to
     * `undefined`.
     */
    const func = co.wrap(function* () {
        yield foo();
        yield bar();
        yield baz();
    });

co works very much like async functions, a proposed ECMAScript feature (to appear in ES2016 or later), without being much more verbose. I prefer it to transpiling async functions via Babel, because their syntax may still change.

Further reading

No comments: