Asynchronous JavaScript

Experiences from my personal journey

Content

  • About me
  • Introduction
  • Callbacks
  • Promises
  • async/await

About me

picture of me

Julian Tölle
Developer @ narando & TrackCode
Backend Development & Devops
Javascript for 13 months

Introduction

Node.js and JavaScript are:

  • single-threaded
  • event-driven
  • non-blocking

Callbacks

    Pros:
  • supported everywhere
  • used in Node.js standard library and most packages
    Cons:
  • hard to keep track of current context (callback hell)
  • decentralized error handling

Callbacks

Example


              import fs from "fs";
              
              fs.readFile("config.txt", (err, config) => {
                if(err) {
                  console.error(err);
                  return;
                }

                console.log(config);
              });

              console.log("Hello World!");
            

Callbacks

Callback Hell


                var p_client = new Db("integration_tests_20");
                p_client.open((err, p_client) => {
                  p_client.dropDatabase((err, done) => {
                    collection.insert({ a: 1 }, (err, docs) => {
                      collection.find({ name: "Donald" }, (err, cursor) => {
                        cursor.toArray((err, items) => {
                          test.assertEquals(1, items.length);
                
                          // Let's close the db​
                          p_client.close();
                        });
                      });
                    });
                  });
                });                
            

Promises

    Pros:
  • supported mostly everywhere no IE11
  • error handling
    Cons:
  • no variable passthrough
  • only slightly less verbose

Promises

Example


              fetch("https://api.coindesk.com/v1/bpi/currentprice.json")
                .then(res => res.json())
                .then(res => res.bpi.USD.rate_float)
                .then(rate => console.log(`Current BTC/USD Rate: ${rate}`))
                .catch(err => console.error(err));
            

Asynchronicity

with promises Pattern


              // Parallel Execution
              Promise.all([
                fetch("https://api.coindesk.com/v1/bpi/currentprice.json"),
                fetch("https://api.coindesk.com/v1/bpi/historical/close.json")
              ]).then(([currentPrice, historicalPrices]) =>
                console.log(currentPrice, historicalPrices)
              ).catch(err => console.error(err));
            

Promises

The ugly side


              // Variable Passthrough
              User.findOne({ name: "realDonaldTrump" })
              .then(user => Promise.all([user, Tweets.find({ user_id: user.id })]))
              .then(([user, tweets]) => {
                console.log(`User ${user.name} has ${tweets.length} tweets`);
              });
            

async/await

    Pros:
  • easy adoption in promise-based code
  • natural error handling
    Cons:
  • only supported since Node 7.6

async/await

Example


              async function getBtcRate() {
                try {
                  const res = await fetch("https://api.coindesk.com/v1/bpi/currentprice.json");
                  const currentPrice = await res.json();
                  const rate = res.bpi.USD.rate_float;
    
                  console.log(`Current BTC/USD Rate: ${rate}`)
                } catch (err) {
                  console.error(err);
                }
              }
            

async/await

Pattern: Parallel Execution


              // Parallel Execution
              async function getBtcData() {
                try {
                  const [currentPrice, historicalPrices] = await Promise.all([
                    fetch("https://api.coindesk.com/v1/bpi/currentprice.json"),
                    fetch("https://api.coindesk.com/v1/bpi/historical/close.json")
                  ])
                  
                  console.log(currentPrice, historicalPrices)
                } catch (err) {
                  console.error(err);
                }
              }
            

async/await

Pattern: Keeping Context


              // Don't loose access to previous results
              async function getUserTweets({ username }) {
                try {
                  const user = await User.findOne({ name: username });
                  const tweets = await Tweets.find({ user_id: user.id });
  
                  console.log(`User ${user.name} has ${tweets.length} tweets`);
                } catch (err) {
                  console.error(err);
                }
              }
            

async/await

Pattern: Functional Programming


              // Mixing async/await with FP
              async function getUserTweets({ users }) {
                try {
                  const tweets = await Promise.all(
                    users.map(user => Tweets.find({ user_id: user.id }))
                  );
              
                  console.log(`A total of ${tweets.length} tweets for ${users.length} users has been returned`);
                  return tweets;
                } catch (err) {
                  console.error(err);
                }
              }
            

Summary

Callbacks

supported by standard library

Promises

foundation for async/await

async/await

most clear and simple code