Promises & Why Your Code Won’t Keep Them
What on earth is async/await
syntax and how do I use it?
One of the very first things that prospective computer science students are taught is that code will do exactly what it is told to do. Students initially become excited by this statement — great, coding is easy! Quickly, however, one comes to realize what exactly code needs to be told, and that, sometimes, it can become quite complex.
Let me introduce you to async/await
, a special syntax of JavaScript used to work with promises. In short, this syntax is a way for engineers to explicitly tell their code when to wait for certain functions to finish executing before moving on.
Async
async
functions return a promise, where this promise allows for other code in your program to run while waiting for your asynchronous function to complete. Otherwise, you need to specify to your program that you’d like to wait for an async
function to finish execution before moving on.
Await
If you don’t await
an asynchronous function’s completion, it’ll simply say “well, I promised I’d return something to you eventually, so here is an [object Promise]
.” However, when attempting to immediately manipulate these functions’ return values, it’s best you wait for promises to be resolved before continuing. And that’s when we use async/await
.
Let’s take a look a closer look at how we can use this special syntax to ensure our code is running smoothly and as expected.
Inside the Function
Below, I’ve initialized an asynchronous function entitled createSheet()
, inside which I use the Google Sheets API to create a spreadsheet, and return it’s URL. Here’s what I found to be successful:
async function createSheet() {
let response = await sheet.spreadsheets.create(request);
return response.data.spreadsheetUrl;
}
Notice the use of the await
keyword. Without it, our Node.js code does not know that it needs to wait for the API call to be finished — for our spreadsheet to be created — in order to continue.
The Sheets API specifies that the spreadsheets.create method returns a newly created instance of ‘Spreadsheet’, from which we can extract certain fields such as its ID or URL. If we did not use await
, the response variable would be an [object Promise]
, and we’d be trying to access the sheet’s URL before the sheet itself was defined…not ideal.
Calling the Function
Since createSheet()
is defined as async
, calling using the await
keyword signifies that we want our code to wait for createSheet()
to fully finish executing before continuing on to other code.
return await createSheet(/**parameters**/);
Think about it this way: we are waiting for a response from our async
function createSheet()
. This function knows that we are waiting on it, so it is promising us that eventually, it will return a value. Patience is a virtue!
Without await, we’d instead be returning an [object Promise]
. Using async/await
ensures that we are obtaining the exact return value we expect from a function, and not preemptively moving on in our code before certain tasks have finished running.
Breaking the Flow
Here’s an explicit example of how, without using await
, your code will not know when to wait for what:
var url = ‘’;let response = createSheet(/**parameters**/).then(res => {
url = res.data.spreadsheetUrl;
console.log('one');
});console.log('two');
return url;
If you take a look inside of your console log, you’ll observe that “two” was actually printed before “one”…hmmm….
This is because, without using async/await, your calling code becomes impatient and proceeds to the return statement before createSheet()
has a chance to resolve its promise. So, your returned URL will simply be an empty string. Sad.
It’s confusing, because in many languages, code does not attempt to move on before a function is finished executing. However, async
APIs like to do their own thing — if you want their code to run sequentially, you have to explicitly tell it to.
With practice, the async/await
syntax quickly becomes second nature, and might actually seem quite simple. Hopefully this post helps save you a couple of hours of mindless debugging.
You can learn more about async/await
and promises by reading its documentation, or by experimenting with coding a Google Cloud Function in Node.js.
It’s true that code will do exactly what you tell it to do. It’s also true that sometimes, code needs to be told additional instructions in order to not lose its patience. If only there were an async/await
equivalent for humans…
You can find all of the code used here in this blog post on my personal GitHub.