Compile Async-Await to Generators and Promises

Async/Await is introduced in ES2017. In order to let ES2017 code run in very old browsers/platforms, ES2017 code need to be transpiled/compiled to earlier versions. Async/await need to be transpiled to older-version JavaScript code. In this post, I will list three ways to do the same thing: 1) async/await [ES2017+], 2) generator function + promise [ES6], 3) callback functions [ES5-]. With a simple example, we can get a taste of how transpilation works.

1. Async/Await

As of today, this is the way to declare and invoke asynchronous functions.

I tried to keep this example as simple as possible. But let’s assume that data3 depends on data2 which depends on data1. “second.url” can be data access on data1, e.g., data1.second.url.

function getData(url, callback) {
    console.log("Process ", url);
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => { resolve(url); }, 1000);
        }
    );
}
 
async function execute(){
    const data1 = await getData("first.url");
    const data2 = await getData("second.url");
    const data3 = await getData("third.url");
    console.log(data3);
}
 
execute();

2. Generator function + Promise

This is the basic idea of how transpiler, e.g., Babel, compiles code to ES6.

function getData(url, callback) {
    console.log("Process ", url);
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => { resolve(url); }, 1000);
        }
    );
}
 
asyncExecute(function* () {
    const data1 = yield getData("first.url");
    const data2 = yield getData("second.url");
    const data3 = yield getData("third.url");
    console.log(data3);
});
 
function asyncExecute(generator) {
    let iterator = generator();
 
    function handle(iteratorResult) {
        const iteratorValue = iteratorResult.value;
 
        if (iteratorValue instanceof Promise) {
            iteratorValue.then(res => handle(iterator.next(res)))
                .catch(err => iterator.throw(err));
        }
    }
 
    try {
        handle(iterator.next());
    } catch (e) {
        iterator.throw(e);
    }
}

3. Callback function

This is before ES6, which is commonly accepted as modern JavaScript.

function getData(url, callback) {
    console.log("Process ", url);
    setTimeout(() => { callback(null, url) }, 1000);
}
 
getData("first.url", function (err, data) {
    if (err) {
        alert("error 1");
        return;
    }
    getData("second.url", function (err, data) {
        if (err) {
            alert("error 2");
            return;
        }
        getData("third.url", function (err, data) {
            if (err) {
                alert("error 3");
                return;
            }
            console.log(data);
        });
    });
})

Leave a Comment