Async - Await
Tags: javascript, programming
Published: 2021-06-29 15:23:54

# Async Await keywords

- how does async-await work
- how does it compare to a Promise
- examples of usage
- pitfalls

In this article I'm going to explore and explain how does **async-await** structure work.
What is the impact on the code and how does it compare to standard javascript Promise.
Then I'm going to demonstrate on couple of examples how the code looks when using Promise and how does it look with **async-await** keywords.
I'm going to mention few pitfalls and tricky parts when using both coding styles.
I'm going to give the links to relevant documentation and specification.


## Introduction

**Async - await** was introduced in Ecmascript specification in 2017 with the goal of simplifying asynchronous flow.


## Basic principles and rules
The asynchronous function is defined with the keyword async, like this:

```js
async myFunction() {
  // body of the function
}
```

The signature of the async flavoured function could be written following:
```js
([...any]): Promise<any>
```

async function can be called from anywhere, however the use of **await** keyword is permitted only from within **async** block.

```js
async myFirstFunction() {
  // some logic
  const partial = await getParialResult(); // calling another async function or function returning promise
  // other logic
  return processPartial(partial) // calling sync function with non promise parameter returning non promise value
}
```
the part `some logic` is executed synchronously. The part `other logic` is executed asynchronously only after
the async function call getParialResult is resolved.


## Relationship with promises
The difference between standard and the async flavoured function is that the async function always returns javascript `Promise` object.
There are few basic rules around this.

### The return statement is not defined
Where the standard function returns `undefined` value, the async function returns `Promise<undefined>` - Promise resolved to `undefined`.
```js
async myFunction() {
  console.log('hi from async function')
}
```

### The function returns (not thenable) value
If the return statement is present and the return value is not a `Promise` and not `undefined`, the value is wrapped in the resolved `Promise`
and returned.
```js
async function myFunction() {
  ...
  return 'hello world'
}

myFunction() // Promise { 'hello world' }
```

Similar behaviour would be this:
```js
function myFunction() {
  return Promise.resolve('hello world')
}
```

### The function return thenable value promise or promise like object
The last case is only a subset of the previous case, however it deserves a special mention.
**The async function  returns Promise** . In this case the interpreter does similar thing again with one subtle but important difference.
`Promise.resolve` will automatically flatten any nested layers if "thenable" object is found. This is not the case of async function return. Here the value wrapped inside promise is unwrapped and wrapped again in new Promise object.

Comparing to Promise.resolve:
```js
const myPromise = new Promise((resolve, reject) => { resolve(42) });
async function myAsyncFunction() { return myPromise }

var p = myFunction()
// p is holding Promise { 42 }

p === myPromise // false
myPromise === Promise.resolve(myPromise) // true, because the nested structure is flattened
```

comparing to standard function:
```js
function mySyncFunction() { return myPromise }

var p = myFunction()
// p is holding Promise { 42 }

p === myPromise // true
```

Should we simulate the behaviour of returning value wrapped in resolved Promise from async function we could write:
```js
function likeAsyncFunction() {
  // value inside promise is unwrapped and wrapped again in new promise object
  return myPromise.then(value => Promise.resolve(value))
}
p = likeAsyncFunction() // Promise { 42 }

myPromise === p // false
```

## So, is it only syntactic sugar?
The first think what crossed my mind was hold on, this is just syntactic sugar for promises. Whatever exists after `await` keyword could go into `then` handler. Is this true?
Few examples ilustrates similarities and differences to promises and perhaps gives you some ideas or notions how to explore async-await structure beyond promises.

### Synchrounous and asynchronous part
I'll ilustrate the nature of typical async function on the following example. It can be executed in nodejs.
```js
// app.js
// run node app.ja

/*
 * this function will be used trhought few more examples, so keep it.
 * when using plain promises the async keyword can be ignored (ref. to the above explanation)
 */
async function sleep(mls) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('resolving...')
      resolve(mls)
    }, mls)
  })
}

async function serviceB() {
  console.log('serviceB:1');
  await sleep(1000)
  console.log('serviceB:2')
}

async function serviceA() {
  console.log('serviceA:1')
  await serviceB()
  console.log('serviceA:2')
}

console.log('before')
serviceA();
console.log('after')
```
the above code will result in the following output
```
before
serviceA:1
serviceB:1
after
resolving...
serviceB:2
serviceA:2
```
serviceA is called (pushed in stack) as regular function. Execution continues as synchronous.
Inside *serviceA* it gets to the first **await** keyword with function call to *serviceB*. Now this function *serviceB* is analyzed and executed.
It is pushed to the stack and executed synchronously until either returns (Promise) or until another **await** function call is found.
What happened to the rest of the function **after** await call?
It is considered as another block of code similar to callback. The block is queued and pushed back to stack once the async operation is finished.

This is a very close equivalent using Promises:
```js
function serviceB() {
  console.log('serviceB:1');
  return new Promise(resolve => {
    sleep(1000).then(() => {
      console.log('serviceB:2')
      resolve();
    })
  })
}

function serviceA() {
  console.log('serviceA:1')
  return new Promise((resolve) => {
    serviceB().then(() => {
      console.log('serviceA:2')
      resolve();
    })
  })
}

console.log('before')
serviceA();
console.log('after')
```
Running it the exact same way as the previous code will yield exactly same output. The console log demonstrates how the both
function *serviceA* and *serviceB* gets to stack and then leave the stack allowing to execute `console.log('after')`.
Once the async part is finished the callback, or the block of code after async is placed on stack and *serviceB* is executed, after that callback or block after async of *serviceA* is placed on the stack and executed.

Besides how it does work these two examples also demonstrate one of the early mentioned benefits of async-await constructs.
The code is more readable and less cluttered with the callbacks.
However, some might argue that synchronous nature of the syntax might produce confusion and some hard to trace bugs.
What I mean by this?
```js
serviceA()
serviceB()
serviceC()
```
If these are all async functions with *await* inside, the order in which the *await* part of the functions complete is independent to the order how these functions are called.
Writing this in the traditional way might better promote the actual behaviour.
```js
serviceA().then(callbackA)
serviceB().then(callbackB)
serviceC().then(callbackC)
```
It is always good to learn how do things work to avoid future confusion.

### FOR loop and similar
treating async code in for loop, particularly when the callback need to run in a sequence can be challenging.
It looks all plain and simple when using `async-await`
```js
async function update(earliestVersion, lastVersion)
{
  for (i = earliestVersion; i <= lastVersion, i++) {
    try {
      await applyUpdate(`version_${first}`);
    } catch(e) {
      throw Error('Update Error')
    }
  }
}

// possible usage in the code:
update(12, 16)
  .then(handleSuccess)
  .catch(handleError)
  .finally(handleFinish)
```

The promise based alternative could work perhaps something like this.
You can already see that it is not that clear how the logic flows, not to mention where and how to handle the exceptions and failures.
```js
function update(earliestVersion, lastVersion) {
  function _update(version){
    return applyUpdate(version)
      .then((res) => {
        if (version <= lastVersion) {
          return _update(version + 1)
        } else {
          return res;
        }
      })
      .catch(() => { throw Error('Update Error') })
  }
  return _update(version)
}
```

### WHILE loop and similar
This is similar case as the for loop. Let's say we are running the hub for wind farm and the server is asking wind turbine to report the status.
In case of sever weather the server need to keep asking for the wind turbine status until the status is retrieved or until number of max tries is reached and alarm is raised.

```js
async function reportStatus(nu) {
  let status = false;
  let tries = 0;
  while (!status) {
    await status = getTurbineStatus(nu)
    logStatusCall(no, status, tries++)
  }
  return status;
}
// usage
turbines.forEach(reportStatus)

// or
Promses.allSettled(turbines.map(reportStatus))
.then(handleResponses)
```
Similar to for loop this will be more challenging to write and test using Promises
```js
function reportStatus(nu) {
  let status = false;
  let tries = 0;
  function _helper(n){
    return getTurbineStatus(n).then((status) => {
        logStatusCall(no, status, tries++)
        if (!status) {
          return _helper(n);
        } else {
          return status
        }
      })
  }
  return _helper(nu)
}
```


### How about generator function*?
Is it possible to combine generator function with **async** keyword? Yes and no to a certain extent.
Here is the example of simple countdown function. It is using *setTimeout*.
```js
async function* countdown(count, time) {
    let index = count;

    while (index) {
        await sleep(time)
        yield --index;
    }
}

async function testCountDown(count) {
  const cd = countdown(4, 1000)
  let val = await cd.next();
  while (!val.done) {
    console.log(`finish in ${val.value}`)
    val = await cd.next();
  }
  console.log('...finished')
}

testCountDown(5)
```
Comparing to *synchronous* generator function there is one key difference. It actually breaks the **iteration protocols** (without await).
Async function always returns a Promise, so the expected object `{ value, done }` is wrapped in the Promise.
It also would not work in `for..of` loop neither it will work with spread operator `[...iterable]`.
Both constructs expects `iterable` and the interpreter can't access the `{ value, done }` object directly.
My advice is don't use the *async* generator functions - if you really have to use them be aware of differences to avoid unexpected behavior and bugs.

### async function as a method
Method is a function bound to an object. So how does async function work as a method, and how does it compare to traditional function returning promise?
Async function simplifies the flow here as well. Unlike promise in promise handler keyword `this` refers to the calling object even in the async part of the block which following after `await` keyword. To refer to `this` from inside the promise handler we need to use arrow functions or to bind `this`.

example:
```js
function logName() {
  console.log(`Hi, my name is ${this.name}.`)
}

class Simpson {
  constructor(name) {
    this.name = name
  }
  logName() {
    console.log(`Hi, my name is ${this.name}.`)
  }
  async waitAndSayHi(time) {
    await sleep(time);
    this.logName();
  }
  waitAndSayHiWithPromise(time) {
    return new Promise(resolve => {
      sleep(time).then(this.logName.bind(this))
    })
  }
}

const lisa = new Simpson('Lisa')
const bart = new Simpson('Bart')

lisa.waitAndSayHi(500)
bart.waitAndSayHiWithPromise(1000)
```
Omitting `.bind(this)` will result in the obvious error for obvious reasons. Something we don't need to worry about when using `async-await`.

## Summary
**async - await** is a handy way how to tackle the asynchronous code. It helps with flow control and it is particularly useful in loops when multiple sequence of asynchronous operations is required.
It improves readability of the code provided the programmer is fully aware of the consequences.
It should be seen as an extension to promise architecture rather then as merely syntactic sugar for *promises*.

## Sources

1. [Async Function Definition](https://tc39.es/ecma262/#sec-async-function-definitions)
2. [Generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator)
3. [Async-Await MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await)