300 JavaScript: Writing asynchronous code [2.5d]

Updated . Posted . Visible to the public.

JavaScript never blocks: network requests, timers and animations run asynchronously. This lesson covers callbacks, Promises and async/await, and how to handle errors in asynchronous code.

Important

Work on this lesson in builder mode.

Learning goals

  • You can explain why JavaScript is single-threaded and non-blocking, and what the event loop does with tasks and microtasks.
  • You can explain the difference between synchronous and asynchronous APIs, and why a network request cannot simply return its response.
  • You can work with callbacks, Promises and async/await, and translate between the three styles.
  • You can explain the states of a Promise, how then/catch/finally chain, and how a rejection propagates through a chain.
  • You can handle errors in asynchronous code, including in event listeners, and explain why throwing from an async function is a trap.
  • You can run several asynchronous operations in parallel and continue when all of them are done.
  • You can explain why asynchrony spreads through a call chain ("colored functions") and what that means for designing an API.
  • You know the browser's scheduling APIs — timers, requestAnimationFrame, requestIdleCallback — and when each fits.

Resources

Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.

Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.

Start here

Promises and async/await

The event loop in depth

Questions to answer while reading

  • What are "synchronous" or "blocking" APIs versus "asynchronous" APIs?
  • Why does fetch() not simply return the response from the server?
  • Why is asynchronous code such a big issue in JavaScript (as opposed to the code we usually write in Ruby)?
  • What are "callbacks" in JavaScript? Can you find examples for libraries that use callbacks to deal with asynchronicity?
  • What are "promises" in JavaScript? Can you find examples for libraries that use promises to deal with asynchronicity?
  • How can you parallelize multiple calls of an async function?

Exercises

Judging asynchronous code

Look at the following code:

async function init() {
  console.log("first")
  await helperFunction()
  console.log("fourth")
}

async function helperFunction() {
  console.log("second")
  await backgroundTask()
  console.log("third")
}

// Stub function that resolves after 100 milliseconds, could be an API call
function backgroundTask() {
  return new Promise((resolve) => setTimeout(resolve, 100))
}

init()

What happens when you remove the await of helperFunction? What happens when you remove the await of init? What causes the new behavior?

Now have a look at this sketched usage of asynchronous functions:

const news = await fetchNews()
renderNews(news)

const recentUsers = await fetchRecentUsers()
renderUsers(recentUsers)

Do you agree with the implementation? If not, what could be improved?

atFullSecond()

Create an implementation of setTimeout that returns a promise rather than taking a callback. Name this new function atFullSecond, as it should wait for the remaining milliseconds until the next second starts. For example, at 13:23 and 441 milliseconds, atFullSecond(1) should wait for 559 milliseconds before triggering the callback function.

Internally, it can make use of setTimeout, but the API should be like that:

atFullSecond(2).then(function() {
  console.log(`waited until exactly ${new Date}`)
})

new Date().getUTCMilliseconds() gives you access to the current millisecond offset.

As a bonus, also reject the promise if the caller passes number smaller than one to atFullSecond.

doubleRandom()

Write a function called doubleRandom that

  • fetches and logs two random numbers from an API
  • returns the sum of those two numbers

You can either implement your own API backend or use the free service at api.random.org Show archive.org snapshot . If you chose the the latter, create an account for it and click yourself a "Developer" API key. Then head over to the documentation of the generateIntegers endpoint Show archive.org snapshot . As learning JSON-RPC is out of scope of this card, you may base your client-side implementation on this code:

fetch('https://api.random.org/json-rpc/4/invoke', {
  method: 'POST',
  headers: {  'Content-Type': 'application/json' },
  body: JSON.stringify({
  jsonrpc: '4.0',
  method: 'generateIntegers',
  params: {
    apiKey: ...,
    // other params described in the API documentation such as "n", "min" and "max"
  }
})

fetch()

Write a function that:

Create three different implementations of your function:

  1. Using callbacks
  2. Using promises and then()
  3. Using promises and async / await

Note that you are expected to use fetch in every variant, even though it does not offer a callback interface.

Profile picture of Henning Koch
Henning Koch
Last edit
Henning Koch
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra Curriculum (2015-08-20 15:01)