Javascript is awesome, I know that and probably you too. Easy to learn and relatively easy to master as well.

Using higher ordered functions is handy and slick, but sometimes its hard to figure out how to use them asynchronously. Hopefully after reading this post you will understand better when you should await and how.

The basics

Higher Order Function

Higher order function, according to Wikipedia, is a function that takes one or more functions as an argument and/or returns a function.

The most commonly used functions are:

Yes, manipulating arrays is in the core of every application, and these nifty little functions are used more than a paper towel in a public restroom.

lets take a look at map

// our array
const arr = [1, 2, 3, 4, 5];

const newArr = arr.map(num => ++num);

// newArr = [2, 3, 4, 5, 6];

This is pretty basic. we have an array of numbers. The goal is to increment every element by one. We use map to loop though all elements and call our mapping function ((num) => ++num ) passing the element into the function. The mapping function then returns the value of the element plus one. map itself returns a new array with all the returned values from the mapping function.

So that's easy and straight forward, but what happens if you need to manipulate each element asynchronously. Say you have an array of user ID's, and you want an array of user objects, you might want your mapping function to call an API to fetch each user.

async/await and Promises

I'll assume that you know about JS Promises. If not, well, this post is probably not for you.

What does the async keyword does? well it automatically wraps the function with a Promise. the returned value will be the resolved argument while throwing an error will be the rejected reason.

async function foo(){
    return true;
}
// is basically the same as
function bar(){
    return new Promise( (resolve, reject) => {
    	resolve(true);
    });
}

// both can be used the same way
foo()
 .then((val)=>{
	// Do something with the resolved value
 });
bar()
  .then((val)=>{
	// Do something with the resolved value
 });

await can then be used in a function that uses the async keyword, therefore no need to chain Promises. It lets you write asynchronous code in a synchronously way. The bottom line is that an async function always returns a Promise. This is crutial to understanding how to use higher ordered functions asynchronously.

async function foo(){
 try{
     const resolvedValue = await someAsyncOrPromiseFunction();
     // do something with the resolved value
 }catch(err){
     // err is the rejected reason/error
     console.error(err);
 }
}
Remember - foo returns a Promise!

Using Higher ordered functions with async/await

Let's look at a basic async function once more

async function(){
	return true;
}

This async function is returning a Promise<boolean> , Not a boolean.

So lets see what happens when we use an async function to map an array

const arr = [1, 2, 3, 4];
//@returns {Promise}
async function incr(num){
	return num++;
}

const results = arr.map(incr);
results is an array of promises

Since the Array.map function is creating a new array (based of the original array) with the returned values of the mapping function, we end up with array of promises.

So to actually get the resolved results  just need to `await` for each element.

`Promise.all` is what we will use. It expects an array of promises, and returns a single Promise with an array of all resolved values. if one or more were rejected, it will reject as well.

const arr = [1, 2, 3, 4];
//@returns {Promise<number>}
async function incr(num){
	return num++;
}

const results = await Promise.all(arr.map(incr));
console.log(results); /// [2, 3, 4, 5]

Let's look at one more commonly used function. Array.reduce. Lets sum all array values asynchronously. Reduce returns a single value. therefore we only need to await for one Promise. But, because our reducer function is returning a Promise we need to await for the resolved value. that's why our initial value is inside a Promise.resolve to mimic the future promises created in each iteration.

const arr = [1, 2, 3, 4, 5];

const reducer = async (accumulator, currentValue) => {
 const accum = await accumulator;
 return accum + currentValue;
};

const result = await arr.reduce(reducer , Promise.resolve(0));

console.log(result); // 15
accumulator in this case is not a number, its a Promise

Conclusion

Always think about what is being returned from these magical functions, And await accordingly. Since you now understand what is going on when using async/await, you can finally tell your co-workers why their code is incorrect 😉.