Sunday, January 19, 2020

Async Await and Promises

As a continuation of my PR for Telescope, I thought I should talk a bit about async/await and the old way of using return new Promise(). Here are a few examples of do's and don'ts:

// Async functions return promises, no need to add await 
// DON"T DO
async function returnsPromise(){
  return await promiseFunction();
}

// DO
async function returnsPromiseFixed(){
  return promiseFunction();
}

//---------------------------------------------------------------------------

// Don't use await when function is not async 
// DON"T DO
function noAsync(){
  let promise = await promiseFunction();
}

// DO
async function noAsyncFixed(){
  let promise = await promiseFunction();
}
//---------------------------------------------------------------------------

// Writing errors
async function f() {
  await Promise.reject(New Error("Error"));
}

// SAME AS
async function f() {
  throw new Error("Error");
}
//---------------------------------------------------------------------------
// Use try catch to wrap only code that can throw // DON"T DO async function tryCatch() { try { const fetchResult = await fetch(); const data = await fetchResult.json(); const t = blah(); } catch (error) { logger.log(error); throw new Error(error); } } // DO async function tryCatchFixed() { try { const fetchResult = await fetch(); const data = await fetchResult.json(); } catch (error) { logger.log(error); throw new Error(error); } } const t = blah(); //--------------------------------------------------------------------------- // Use async/await. Don't use Promises // DON"T DO async function usePromise() { new Promise(function(res, rej) { if (isValidString) { res(analysis); } else { res(textInfo); } if (isValidStrinng === undefined) { rej(textInfo); } }) } // DO async function usePromiseFixed() { const asyResult = await asyFunc() } // -------------------------------------------------------------------------- // Don't use async when it is not needed... Don't be overzealous with async/await // For example the sentiment module we're using is not an async function // DON"T DO module.exports.run = async function(text) { const sentiment = new Sentiment(); return Promise.resolve(sentiment.analyze(text)); }; // DO module.exports.run = function(text) { const sentiment = new Sentiment(); return sentiment.analyze(text); }; // -------------------------------------------------------------------------- // Avoid making things too sequential // DON"T DO async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } } // DO async function logInOrder(urls) { // fetch all the URLs in parallel const textPromises = urls.map(async url => { const response = await fetch(url); return response.text(); }); // log them in sequence for (const textPromise of textPromises) { console.log(await textPromise); } } // --------------------------------------------------------------------------
// Examples
// refactor following function:

function loadJson(url) {
  return fetch(url)
    .then(response => {
      if (response.status == 200) {
        return response.json();
      } else {
        throw new Error(response.status);
      }
    })
}

// Solution:
function loadJson(url) {
  let fetchResult = await fetch(url);
  if (fetchResult.status == 200){
    let json = await fetchResult.json();
    return json;
  }

  throw new Error(fetchResult.status);
}

// refactor to use try/catch
function demoGithubUser() {
  let name = prompt("Enter a name?", "iliakan");

  return loadJson(`https://api.github.com/users/${name}`)
    .then(user => {
      alert(`Full name: ${user.name}.`);
      return user;
    })
    .catch(err => {
      if (err instanceof HttpError && err.response.status == 404) {
        alert("No such user, please reenter.");
        return demoGithubUser();
      } else {
        throw err;
      }
    });
}

demoGithubUser();

// Solution:
async function demoGithubUser() {
  let user;
  while(true){
    let name = prompt("Enter a name?", "iliakan");
    try {
      user = await loadJson(`https://api.github.com/users/${name}`)
      break;
    } catch (err) {
      if (err) {
        alert("No such user, please reenter.");
        return demoGithubUser();
      } else {
        throw err;
      }
    }
  }
}

// Call async from non-async
async function wait() {
  await new Promise(resolve => setTimeout(resolve, 1000));

  return 10;
}

function f() {
  // ...what to write here?
  // we need to call async wait() and wait to get 10
  // remember, we can't use "await"
}

// Solution:
function f() {
  wait().then(result => alert(result));
}

No comments:

Post a Comment

Contains Duplicate (Leetcode)

I wrote a post  roughly 2/3 years ago regarding data structures and algorithms. I thought I'd follow up with some questions I'd come...