Reputation: 12636
This question is theoretical - I have no concrete problem to solve.
With that said, why does the async
keyword wrap the return value of an async function in a promise? What's the point? Is it ONLY because the await
expression expects a promise? Or is there some meaning / use behind this decision?
Upvotes: 0
Views: 2117
Reputation: 1163
I thought i'd answer this primarily because async in Javascript used to confuse the hell out of me, and all of a sudden it snapped, so i hope this analogy may help this happen for you.
You have an async event. This could be anything, getting something from a server, doing something in the browser that takes time, training a machine learning model (!), executing a function or method that uses a setTimeout etc.
The beauty of Javascript and a key reason it works so well for the browser is that it uses the processor thread it runs on in a very clever way that stops the thread from getting blocked by processes that take time (like the ones mentioned above)
Many other languages, for example Ruby run on more than one thread. It is possible to use service workers to run processes on multiple threads in javascript but that is outside the scope of this answer!
The async nature of the JS event loop allows the thread to 'go off' and do something else while it is waiting for a process to finish.
The problem with this from a programming point of view is that it is possible for something in the code that relies on the result of a blocking event to get 'undefined' as a result of the event if it doesn't wait for the event to finish before it tries to use the result of it. Take this piece of code below
let scopedVariable
console.log('the code has started')
setTimeout(() => {
scopedVariable="I am the result of some async process"
}, 5000);
console.log(scopedVariable)
When the code reaches the console log, the setTimeout hasn't yet completed. As the setTimeout sets the scopedVariable only when it completes, the variable is undefined when we log it
We wrap the timeout in a promise we can await it's resolve callback (first argument of promise) and the code will 'pause' until the promise reaches the resolve callback before continuing.
When we await the promise and the setTimeout completes, the resolve function sets the variable, so that when we console log it it holds the value from the promise
let scopedVariable
const asyncEvent = new Promise ((resolve,fail) => {
setTimeout(() => {
resolve(scopedVariable="I have resolved")
}, 5000);
})
const container = async () => {
const result = await asyncEvent
console.log(scopedVariable)
}
container()
You can use await and .then interchangably
For example we could go:
let scopedVariable
const asyncEvent = new Promise ((resolve,fail) => {
setTimeout(() => {
resolve(scopedVariable="I have resolved")
}, 5000);
})
const container = async () => {
asyncEvent.then(() => console.log(scopedVariable))
}
container()
once again the code will pause at .then and then continue when the asyncEvent promise has resolved.
In fact if we use .then we don't need to enclose it in an async function so we can rewrite it like this
let scopedVariable
const asyncEvent = new Promise ((resolve,fail) => {
setTimeout(() => {
resolve(scopedVariable="I have resolved")
}, 5000);
})
asyncEvent.then(() => console.log(scopedVariable))
The great thing about .then is that the accompanying .catch allows you to catch any errors thrown by the async event (for example if retrieving something from a server when there is an error). For async await you need to wrap potentially dangerous functions in a try catch.
In order to use await you need to be inside an async function (hence the async container function above). This is not necessary with .then, but .then and .catch chains can make your code messy.
I hope this helps!
Upvotes: 4
Reputation: 780798
The async
and await
operators are just syntactic sugar that hide the underlying use of promises to implement asynchronous code.
Using async
before a function definition makes the function return a promise that resolves to the function's return value, rather than returning normally.
Using await
before an asynchronous function call suspends the current function until the promise that it returns is resolved. It's basically equivalent to wrapping the remainder of the function in an anonymous function, and using that as the .then()
callback of the promise.
For more information between the relationship, see How to translate Promise code to async await
Upvotes: 3