Patterns for Dealing with Async Code
We are going to use setTimeout
to simulate asynchronous call to a database and async network requests. Consider the following scenario:
- We look up a user in our database to collect its bank account number.
- We send a HTTP GET request to a bank, providing the account number, to receive a list of loans associated with the given account.
- After the list of loans were received, we will send a second request to get a complete transaction history (e.g. payments, etc) associated with the most recent loan.
Don't get hung up on the irrelevant details such as what if there are no loans associated with the account, etc.
Let's start by (simulation of) getting a user object from a database.
function getUser(id) { console.log("Reading a user from a database..."); setTimeout(() => { console.log("Received user data..."); return { "ID": id, "Account number": "58721094531267" } }, 2000); } console.log("listening for events"); getUser(1); console.log("still listening for events!");
Let's try to store and display the user returned from the database:
function getUser(id) { console.log("Reading a user from a database..."); setTimeout(() => { console.log("Received user data..."); return { "ID": id, "Account number": "58721094531267" } }, 2000); } console.log("listening for events"); const user = getUser(1); console.log(`user: ${user}`); console.log("still listening for events!");
The user
object is undefined
because the return statement in getUser
is executed (at least) two seconds after it was called. So what is returned from getUser
will not be available at the time of calling it.
So how can we access the user
returned from getUser
function? There are three patterns to deal with asynchronous code:
- Callbacks
- Promises
- Async/await
We will look at each in the following sections.