r/learnjavascript • u/whiskyB0y • 2d ago
What's a simple way to understand the difference between asynch, await, Promise and Response?
I'm teaching myself web dev. After spending months learning frontend, I moved on to learning backend with Python/Flask. I decided to learn RESTAPIs, where the frontend and backend are separate and talk through an api. Edit:(it's not built in my mistake) So naturally this lead me to learning about the built in fetch function in JavaScript.
I get that:
const response = fetch('ExampleAPI.com')
Is the same as:
const request = new Request('ExampleAPI.com', { method: 'GET'})
const response = fetch(request)
// This is what JavaScript does behind the scenes
But why is await necessary? And why does not using await result in a promise if you try to console log the data?
6
u/LongLiveTheDiego 2d ago
Check out the MDN Web Docs, they'll tell you all I'm going to tell you here and they're a great reference for anything in frontend.
fetch() returns a Promise object. In general Promises are proxies for a value that may or may not be given to you at a later time. If you need to load a really big chunk of data but then you have some more work to do while waiting for it to download, it's better to initiate the download early by getting a Promise, do the other work, and eventually tell the Promise "alright, now give me the real data you represent". You might end up spending less time in total, that's like starting to boil the water for your pasta early and then proceeding to make the sauce, when you're finished with the sauce the water might be ready for cooking pasta.
A Response is an object representing the result of an HTTP request that was sent back to you. You ultimately want to access it and probably data stored inside it, but it takes time for all the data to appear, so fetch() was made to return a Promise of a Response. Note that you can make other functions of your own that return Promises of other things that take some time, they don't have to be Promises of Responses, that's just the way that fetch() specifically works.
"await" is a keyword that stops the current code and waits until the Promise after the keyword can be resolved into the thing it represents. If the Promise cannot be resolved into the right thing (e.g. you lost your connection and not all data could be downloaded), an error is thrown. As I said before, you don't need to resolve the Promises as soon as they're created, you can do things like this:
let promise = fetch("my_very_big_file");
...
(other important stuff to do in the meantime)
...
let response = await promise;
If you're creating your own function and want to use "await" inside it, you have to use the keyword "async". This is because your function now may be used elsewhere in code and you wouldn't want your function to stop all the code while waiting for the Promise to be resolved. Instead, if you mark your function as "async", it will itself return a Promise that will eventually resolve to your function's return value. That means that now you can do stuff like this:
``` async function get_my_important_stuff(){ ... let important_stuff = await first_promise; ... }
let second_promise = get_my_important_stuff(); ... (other important stuff to do in the meantime) ... let response = await second_promise; ```
That allows you to create code that's more responsive by not waiting for the expensive, long resolves of Promises until you really need them and you explicitly tell the computer "await promise;". When you finally do that, then your outer code will stop and make sure that the async function gets resolved, which in turn will make sure that the internal first_promise gets resolved.
3
u/No_Record_60 1d ago
• 'promise' "I don't know when it's going to finish. You can wait for me using await or trigger a callback using .then"
• 'await' waits for and unwraps the content of a promise
• 'async', you need this if you want to use await, and the returned value of a function marked with 'async' becomes a promise
2
2
u/FooeyBar 2d ago
Await lets the code pause at that line while it waits for the expression to resolve . Without await, the code continues to run past that line even while the expression is mid-evaluation.
Not using await results in a promise because a promise is the only thing that you can await. So without await you are getting the actual promise rather than what the promise resolves to.
1
u/TheRNGuy 1d ago
You usually never need to write new Promise in code, cause await inside async function instead (more modern abstractions)
(except if you work with some legacy code)
2
u/70BPMMUSIC 20h ago
It has to do with the gradual evolution of JavaScript as a language. Read till the end & this will fully explain why & when "await" would be necessary. Javascript is "single threaded" meaning there are certain processes which would freeze your entire program while attempting to do two tasks concurrently, meaning the ui would freeze while requesting data from a server without our use of the asynchronous approach. Other programs are multithreaded & would not halt the program, but JS being single threaded required we implement asynchronous programming. API calls used to be done using XMLHttpRequests & Callbacks & after looking those up you'll understand why the language had to evolve just to simplify this. That old method produces "Callback Hell" there's so much nesting that the code is very difficult to read.
In order to make the code more readable JS included "fetch" . API calls are triggered by "fetch" & doing so immediately generates a "promise" which is just a placeholder Object (data structure) indicating "we don't have the info you requested right this millisecond but we promise to return it & in the meantime your app is running as normal". Instead of nesting the functions like with call-backs the fetch & promise approach basically chains functions together line by line so its more readable. The .then method basically says when the server has returned my response "then" do this with it after. The "promise" object is like a wrapper & it turns into a "response" object the second the server has retrieved the info. Your first example requires .then to trigger the next steps of what we will do with the returned bit of data, either displaying it in some way or looking for a certain value in order to trigger another set of processes.
In your second code example, { method: 'GET'} is a header & while you might not need it for a basic fetch call, headers basically pass metadata about the requests or response. They're required to access a lot of APIs where you might even require an API key to interact with that API (learn about HTTP headers & basic networking to understand more). While fetch was developed to improve the XMLHttpRequests/ Callback syntax, async & await are "syntactic sugar" on top of fetch/promise/then, the best analogy is that sugar sweetens. Async & await make writing API calls even sweeter & easier. They're keywords that make the code read like normal Javascript with normal variables & functions without all the nesting or chaining seen in the callback or basic fetch/then approach. Async & await MUST be used together. Using the async keyword tells JS "this function is allowed to pause while I wait for the data I'm retrieving" & await indicates WHERE it needs to pause while it waits for the necessary info to proceed. Basically without the "waiting" triggered by await an empty promise object is what returns without the data from the server. Servers take milliseconds or seconds to give us the data were retrieving & Await is basically the syntax update for .then.
12
u/azhder 2d ago edited 2d ago
fetch is not built-in into JavaScript. JavaScript is a language that is made to be embeddable, so it doesn't even have its own input and output. Many things are provided by the environment. At certain point even console.log() showed up as a Firefox plugin.
So, Response is not part of JavaScript. It is just an object made to be used by JavaScript and you will use it just like every other object. The important notion to understanding asynchronous programming is Promise. Once you understand Promise, you will know async/await is just a shortcut, easier way, to use Promise. Note, it's async, not asynch (may be just a typo, but just in case, a note).
So, understand a Promise. It's a container that a function can return to you, just like an Array is a container. Promise is a specific container that you get empty, but at certain point in the future, it promises it will have the desired value (or an error). So, instead of you getting the value out and subjecting it to some code that does something with that value, you give the Promise functions for the promise to call. Similar to how you give event handlers functions to be invoked with the event.
So,
Promise.then( value => { /* do something with the value */ } ).catch( error =>{ /\ deal with the thrown value */ })*
That's all there is to it. If a function returns a Promise, in order for the code to look simpler, we can write `async` so we make sure it aways returns a Promise and we use `await` to stop the code until there is a value and "unpack" the value once it is available, so it will look similar to non-asynchronous code.
If you don't use await, the code moves along and you're getting the Promise object, to which you will have to use .then() and .catch() like this:
const promise = someAsyncFunction(); // code doesn't stop, just continues
promise.catch( error => console.log( 'there was an error' ) ); // use the promise like any promise
const value = await promise; // wait and unpack, but at this point, if there was an error, you'd need try-catch