Async/await is a new syntax that comes with es7, which enables asynchronous code to be written synchronously. The example below illustrates how the new syntax compares to just using promises.

// with async fns

// Note: we are using a promisified version of request and readFile

async function fetchAndReadAsync(url, dir) {

var data = await requestPromise(url);

var fromFiles = await readFilePromise(dir, ‘utf-8’)

return [data.body, fromFiles];

} async function run() {

var fromAsyncFunctions = await requestAndWriteAsync(“/foo.txt”, “https://www.foo.com/bar") return valsFromAsyncFunctions;

}

run()

.then(success => console.log(success))

.catch(err => console.log(err.message, err.stack)); // with promises

function fetchAndReadPromise (url, dir) {

var dataBody;

return requestPromise(url).then( ( data )=> {

dataBody = data.body;

return readFilePromise(dir, ‘utf-8’);

}).then( ( fromFiles ) => {

return [dataBody, fromFiles];

}) } function run() {

var fromPromises;

return run(“/foo.txt”, “https://www.foo.com/bar").then((data) => {

fromPromises = data;

return fromPromises;

})

} run()

.then(success => console.log(success))

.catch(err => console.log(err.message, err.stack));;

Some may argue that async/await syntax does away with the need to understand promises, which is somewhat true since it does a decent job abstracting out the Promise implementation.

I find, however, that an understanding of Promises allows a powerful form of asynchronous functional programming with async/await that you can only get with Javascript Promises.

A surprising lifting mechanism with async/await

An interesting thing to note is that though the async/await syntax is used for asynchronous functions, the async function itself runs synchronously and returns a Promise.

var request = require('request'); var requestPromise = util.promisify(request); async function fetchAsync(url) {

var data = await requestPromise(url);

return data;

} var pendingPromise = fetchAsync(‘https://foo.com'); console.log(pendingPromise) // Promise<…Pending>

The returned value of the async fn is not the returned ‘data’ variable, but a ‘pending Promise’ that will, when resolved, pass the ‘data’ variable into the ‘then’ function property. So we could access the data like this.

fetchAsync(‘https://foo.com')

.then(function(data) {

console.log(data) // {body: [object Object]}

})

The key here is that fetchAsync returns a pending Promise, meaning that the return value of the fetchAsync function can also awaited

async function run() {

var data = await fetchAsync(‘https://foo.com');

return data;

}

This allows us to use a FP paradigm called ‘lifting’. Lifting is the conversion of data from one form to another. Array.prototype.map, for example, takes an array and lifts it to another form of the array. (A functional programming fun fact, a map is defined as a function that performs a lift)

Correction: As mentioned in the comments, Array.prototype.map does not lift one array to another, but rather lifts a function that is meant for a single entry to be able to be applied to an array of that entry.

Here is an example of a lift using our ‘fetchAsync’ function from above

var request = require('request');

var fs = require('fs'); var requestPromise = util.promisify(request);

var writeFilePromise = util.promisify(fs.writeFile); // mapToWriteFile will lift our pending fetch promise to a

// pending fetch and write promise

async mapToWriteFile(pendingFetch, dir) {

var data = await pendingFetch;

var written = await writeFilePromise(data, dir);

return written;

} async function run() {

var pendingFetch = fetchAsync('https://foo.com');

var pendingFetchAndWrite =

mapToWriteFile(pendingFetch, '/foo.txt');

var success = await pendingFetchAndWrite; // fs.writeFile does not pass a value into it’s ‘then’ function

// property, but in case that it did the return value would be

// thenable with the success message. return success;

} run()

.then(success=> console.log(success))

.catch(err => console.log(err.message, err.stack));

In this example we lifted the requestPromise using the mapToWriteFile function, yielding a pending Promise that will resolve after both data fetch and file write are done.

This integrates into the Javascript functional programming system quite well, as we can see from a more advanced example.

import urls from ‘./modules/urls’; // array of urls

// the fetchAsync function is taken from the previous example async function run() {

var pendingFetches = urls.map(fetchAsync);

var pendingWrites = pendingFetches.map( pendingFetch =>

mapToWriteFile(pendingFetch, ‘/foo.txt’)

);

var success = await Promise.all(pendingWrites);

return success;

} run()

.then(success => console.log(success))

.catch(err => console.log(err.message, err.stack));

A surprising immutability guarantee

An interesting thing to note is that async functions don’t actually run our asynchronous code; they only promise that the code will run as the event loop turns.

Meaning that an async function can guarantee no side-effects in the current call stack. For example:

async function run( mutableData ) {

var data = await fetchAsync(‘https://foo.com'); //this change doesn’t go into effect in the current call stack

mutableData.prop = data.body;

} run();

So when we pass data into an async function, we can safely assume that it won’t be mutated as we run through the call stack.

A caveat: code written above the first ‘await’ keyword is run synchronously, so as long as one avoids mutating the input above the first ‘await’ keyword (which would be unusual), the guarantee applies.

This has been my experience with async/await so far, there are other functional programming utilities that I haven’t explored like currying and function composition. But until next time…