ES6 async/await

tl;dr: just like async/await and Tasks in C#, Promises in ES6 can allow us to have synchronous-looking asynchronous code and forever kill callback hell.


In ES6 Promises are a way of handling asynchronous operations without needing to use traditional callback-style code. For example take this contrived node example using the fs module:

// Ex. A
fs.readFile('data.csv', {}, function (err, data) {  
    if (err) {
        throw err;
    }
    else {
        console.log(data.toString());
    }
});

and if it supported returning a Promise, the above would become:

// Ex. B
fs.readFile('data.csv', {})  
  .then(function (data) {
      console.log(data.toString());
}).error(function (err) {
    throw err;
})

which is all well and good especially if you have sixty nested asynchronous operations (that would be hell) in which you could chain the then(). But thinking about another language I love, C#, which in the 5.0 version of the language introduced the async and await keywords, a similar example would be:

// Ex. C
using (var reader = File.OpenText("data.csv"))  
{
    Console.WriteLine(await reader.ReadToEndAsync());
}

you could also cheat by not worrying about the disposable stream of reader and compress it down to just one line: Console.WriteLine(await File.OpenText("data.csv").ReadToEndAsync());. Pretty awesome, no?

Well I had an idea about how to introduce the await keyword to ES6 and it combines the promises mentioned above (Ex. B):

// Ex. D
var data = await fs.readFile('data.csv', {});  
console.log(data.toString());  

That would be killer, right? It would necessitate some source rewriting so that the above example (Ex. D) would be transformed into the promises-based example above (Ex. B). The problem is that anwhere that the await keyword is used, you would need to add yet another function enclosing the remaining scope after the await keyword. For example take this little less contrived chunk:

// Ex. E
function doThingSemiSync (x) {  
    let y = await doThingAsync(x);
    return x + y;
}

Seems straightforward enough, but if you look at how it would transmogrify into something promises-based, it becomes:

// Ex. F
function doThingSemiSync (x) {  
    doThingAsync(x).then(function (y) {
        return x + y;
    }).error(function (err) {
        throw err;
    });
}

Shit. Maybe it would be better if we did something like this:

// Ex. G
function doThingSemiSync (x) {  
    return new Promise(function (reject, resolve) {
        doThingAsync(x).then(function (y) {
            resolve(x + y);
        }).error(reject);
    });
}

So basically we're returning a Promise now which almost exactly mirrors what C# does with async and await (although it uses a Task instead of a Promise). You could even add some sugar to the langauge adding the async keword which would require that a function returns a Promise:

// Ex. H
async function doThingSemiSync (x) {  
    ...
}

At some point you would need to deal with a Promise directly, but I think a nice, flat and synchronous-looking function looks a helluva lot better than the alternatives of callback hell and raw promises.