Async Await
 Modern JavaScript added a way to handle callbacks in an
 elegant way by adding a Promise based API which has special
 syntax that lets you treat asynchronous code as though it
 acts synchronously.
 Like all language features, this is a trade-off in
 complexity: making a function async means your return
 values are wrapped in Promises. What used to return a
 string, now returns a Promise
// You can use the await keyword to convert a promise
 into its value. Today, these only work inside an async
 function.
const func = () => ":wave:";
const asyncFunc = async () => ":wave:";
const myString = func();
const myPromiseString = asyncFunc();
myString.length;
// myPromiseString is a Promise, not the string:
myPromiseString.length;
// Code which is running via an await can throw errors,
 and it's important to catch those errors somewhere.
const myWrapperFunction = async () => {
  const myString = func();
  const myResolvedPromiseString = await asyncFunc();
  // Via the await keyword, now myResolvedPromiseString
  // is a string
  myString.length;
  myResolvedPromiseString.length;
};
// We can wrap calling an async function in a try catch to
 handle cases where the function acts unexpectedly.
const myThrowingFunction = async () => {
  throw new Error("Do not call this");
};
// Due to the ergonomics of this API being either returning
 a single value, or throwing, you should consider offering
 information about the result inside the returned value and
 use throw only when something truly exceptional has
 occurred.
const asyncFunctionCatching = async () => {
  const myReturnValue = "Hello world";
  try {
    await myThrowingFunction();
  } catch (error) {
    console.error("myThrowingFunction failed", error);
  }
  return myReturnValue;
};
// Then the function consumers can check in the response and
 figure out what to do with your return value. While this
 is a trivial example, once you have started working with
 networking code these APIs become worth the extra syntax.
const exampleSquareRootFunction = async (input: any) => {
  if (isNaN(input)) {
    throw new Error("Only numbers are accepted");
  }
  if (input < 0) {
    return { success: false, message: "Cannot square root negative number" };
  } else {
    return { success: true, value: Math.sqrt(input) };
  }
};
// getResponse(url, (response) => {
   getResponse(response.url, (secondResponse) => {
     const responseData = secondResponse.data
     getResponse(responseData.url, (thirdResponse) => {
       ...
     })
   })
 })
 And let it become linear like:
 const response = await getResponse(url)
 const secondResponse = await getResponse(response.url)
 const responseData = secondResponse.data
 const thirdResponse = await getResponse(responseData.url)
 ...
 Which can make the code sit closer to left edge, and
 be read with a consistent rhythm.
const checkSquareRoot = async (value: number) => {
  const response = await exampleSquareRootFunction(value);
  if (response.success) {
    response.value;
  }
};
// Async/Await took code which looked like this: