JavaScript Promises and Async
Asynchronous Code
JavaScript programs are often split up into many itty-bitty pieces of code — or more precisely, functions. As an asynchronous language, JavaScript’s functions are divided into two groups: what runs now and what runs later.
The asynchronous nature of JavaScript means that our programs will not always execute linearly, or even in the expected order. There may be a data request that takes longer, a piece of code that waits for user input, or a slow response from the network — all of these situations could impact the order in which code executes, ultimately altering passed in data, arguments, and future inputs.
To simulate an asynchronous call for data, I’ll use the setTimeout()
function. Let’s pretend our data call takes 2000 milliseconds to return the request.
The console.log()
‘s are numbered in the order of how I would hope they run. But what actually happens? Let’s see:
It went: 1, 2, 4, 5, 3…. So, what happened? The browser logged 1 and 2, set the timeout function, but, realizing there were other things to be interpreted, impatiently jumped to 4 and 5, messing up the return of our cheese data.
Callback functions, Promises, and Async/Await to the rescue?
Callback me, maybe?
A standard technique for dealing with async code, callback functions make it so the next function is dependent on the information from the previous one. It ensures a sort of linearity through nested functions. With more recent developments in JavaScript, solving async with callback functions is generally avoided… because, well, your code might end up looking like this:
Let’s make a Promise
Repeat after me:
“I solemnly swear to use promises and skip callback hell”
What’s a promise?
Like the name implies, a promise is a chunk of code that promises to resolve, sometime in the future. From MDN (ok, altered a little) here’s what the basic Promise syntax looks like:
var promiseMeCheese = new Promise(function(resolve, reject) {
setTimeout(resolve("Yay, cheese!", 1000, "foo");
});promiseMeCheese.then(function(returnCheese){console.log("WOW! " + returnCheese)}
// "WOW! Yay, cheese!"
The new Promise
takes in arguments of resolve and reject, special functions that will return the value that is passed in to resolve, assuming the promise is not rejected.
Let’s see this in action with our ordered cheese call:
So, we got the cheese we were promised, what more could we ask for?
ASYNC/AWAIT
In one final step to refactor and simplify the code, JavaScript introduce async functions.
var promiseMeCheese = new Promise(function(resolve, reject) {
setTimeout(resolve("Yay, cheese!", 1000, "foo");
});async function mainCheese(){
const returnCheese = await promiseMeCheese
console.log("WOW! " + returnCheese)
}
Again from MDN:
When an
async
function is called, it returns aPromise
. When theasync
function returns a value, thePromise
will be resolved with the returned value. When theasync
function throws an exception or some value, thePromise
will be rejected with the thrown value.
With the await expression, the async function pauses until the promise resolves.
Charcuterie, anyone?
Sources:
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Learn Co: https://learn.co/tracks/accelerated-bootcamp-prep/week-2/databases-and-sql/node-promises-async-await
You Don’t Know JS: https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch2.md