Promise questions
Hey, I have a couple questions about promises-
1) how does the promise object pass in the values to the resolve and reject parameters in
const example = new Promise((resolve, reject) => {…})
? I understand they are methods within the promise object so does that mean the function you pass in is a callback and that callback is used within the object somewhere and they pass them in via that?
2) I see people chain on promise methods to a function that returns a promise e.g. fetch(…).then(…)
. How is fetch for example able to use that promise method since it isn’t a promise object or assigned a promise object such as a variable? I understand it returns one but that doesn’t mean it’s equal to one right? Unless it does?
Thanks in advance.62 Replies
I understand they are methods within the promise object so does that mean the function you pass in is a callback and that callback is used within the object somewhere and they pass them in via that?Yes
I understand it returns one but that doesn’t mean it’s equal to one right? Unless it does?It's a bit of a semantics issue... is exactly the same as The way it works in the background is that for chaining, each step of the chain is resolved, and then replaced with its result, then the next step of the chain is resolved, and so on, until the entire chain is resolved
be EXTREMELY careful when saving a promise to a variable
when you do
.then()
, you are creating a new promiseAh okay that clears it up, thanks.
What could mess up when you save it in a variable?
from my experience, it just behaves super weird if you try to re-use that variable for other
.then()
or doesnt do anything at all
just chain the methodsHm okay, that’s strange
it is weird as hell
Another thing I caught, the resolve and reject functions only take regular values right? Like a string, thrown error, etc.
It wouldn’t make sense to be able to run a function on resolve or reject since that’s what .then and .catch are for right?
no, they take anything
So is .then used to create another promise with the data the first promise returned? And you’d use resolve for just either a message or a function that doesn’t use the data or that you want to run anyway when it’s done or something?
what do you mean?
So if I can run a function inside of resolve, then I can basically say “if this promise completes then run this”. But I can also do that with .then right?
So would you use .then to run a function with the data the promised returned since the promise object would then be equal to the result due to chaining therefore it could access the data but the resolve couldn’t so you’d use that for a regular function you’d want to run on complete?
So from that, since you mentioned that .then creates another promise, would .then be used for creating another promise using the data the first returned etc?
not quite
when you create a promise, you receive 2 arguments: the resolve function and the reject function
when you run
.then
or .catch
, you create a whole new promise
but that is internal
what happens when you run the resolve function is that the value you pass to it will resolve the next .then
with the same value
after that, the value returned in .then
is passed to the next .then
until everything is doneSo it’s used to pass the data returned by the original promise around so you can do something with it in the .then block?
no, it resolves the promise
resolving the promise is like saying "i did everything, i got no errors, here's some data to pass along. adios!"
Yeah that’s what I mean with the data bit. It resolves the promise but I assume the data to pass along is the data returned via the promise right? Because you’re passing it along to “then” do something else with it?
no, it's the data passed to the resolve argument
Hm, I’m a little confused on what you’d put there then other than a completion message, if you were to put a function, what may that be and how would you use it in the then block?
it can be anything
literally
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#loading_an_image_with_xhr
check that
okay, imagine this
im given a task to measure a terrain and take some information about the house and soil
im given 2 folders with papers: the resolve folder and the reject folder
i write all the information on a paper sheet and put it in the resolve folder
i then call my manager and hand him the resolve folder with all the house information
that promise is resolved and i've passed data to it
now, my boss takes me to a lake, and i have to do the same measuring
i cant measure an house because it's water
i cant measure the terrain because its water
so, i fill the reject folder and call my boss
or, i just call him directly and say "i cant measure houses that dont exist, specially on lakes"
that is an error thrown, and the promise halts there
it was rejected anyway, but by an error
Ahh okay that and the example in the link makes sense now. I appreciate you explaining that.
you're welcome
apologies for the ping. Do you know of any resources where i can look into the functionality of that form of chaining where it's replaced with it's result? When i try to look for it it just comes up with adding multiple methods on the same line like .x.y.z haha
that's how any chaining works, it's just a different way of thinking about it
each link in the chain represents the return value
it's the same for fetch, any other function that returns a promise, or stuff like the array methods that return arrays or strings
or jquery
$('div').first().text('hi!').css({color: 'red'}).hide().fadeIn('fast');
ohh okay i see, thanks
you can implement it really easily
just make a class that returns
this
in it's methodsah okay. What if you chain a method on to a function that doesn't return anything? will it just not do anything or be smart enough to gather a value?
it will throw an error saying
blah blah blah is not a function
it'll complain that property blah is not defined, actually
if you don't return anything from a function, its return value is
undefined
. When you try to call a method or access a property on undefined
, it says Uncaught TypeError: function_name_returns_nothing() is undefined
as for "is it smart enough", the answer is always no
code doesn't do anything you (or someone else) didn't explicitly tell it to doah okay i see, i see
depends on what you return
i was just thinking, if promises are mostly used to retrieve info from another source, most functions/methods that allow for that such as
fetch
already return promises, so is there really a need to write them fresh yourself when you can just chain on a .then
to fetch
for example?you started wrong
promises are to do any work
it's just something that may finish in the future
however, you can just use async functions, which are 80% of what you need
so i don't necessarily have to fetch something in there, i can add two numbers for example if i want that to run asynchronously for some reason?
you can do anything
ah okay then
i was looking more into this as well, if i run a method on a variable with a number then it works of course, which must mean it returns something, but how would that return be represented since i assume it wouldn't just be
return xyz
at the bottom of a function since it's a variable?
that's an internal function
so assigning a variable is actually a function with a return of the variable value?
no, assigning a variable is assigning a variable
it's not a function, it's not a return
it's just a variable being created and given a value
Ah. But since I’m chaining on a method to the variable then the variable must return something in order to be equal to it in the chain right?
no, it doesn't return anything
however, it is converted to an instance of a number object
oh okay so i assume by this you mean that since everything in js is an aboject, you're able to call this because this method is included in the object but if you were to call something that wasn't it wouldn't work since there's no return?
well, the number may be automatically optimized and stored as a simple value (often called a "scalar", and it includes numbers, booleans and strings), instead of being a full object
doing that saves a lot of performance and memory
ah okay, but the scalar can include methods?
no
it is internally converted to an object, during execution
ahh okay
gosh everything is very complex with js haha
Ok, I'm gonna give this a try.
1) how does the promise object pass in the values to the resolve and reject parametersYou pass them in yourself within the
Promise
constructor.
Promises, by themselves, are building blocks for you to write your own async code. The fetch()
function, for instance, makes and resolves/rejects a promise under the hood. Because it's built to be a promise. But when using the constructor you need to decide what constitutes a success (call resolve
) or failure (call reject
).
2) I see people chain on promise methods to a function that returns a promise e.g. fetch(…).then(…). How is fetch for example able to use that promise method since it isn’t a promise object or assigned a promise object such as a variable?Ah, but
fetch()
is a promise!
The–MDN docs onfetch()
method of theWindow
interface starts the process of fetching a resource from the network, returning a promise that is fulfilled once the response is available.
fetch
What could mess up when you save it in a variable?Promises are asynchronous code, so the biggest issue with saving it to a variable is that there's no guarantee that it'll hold a value later in your code if you reference it. That's why you always do any work with the data in the promise chain inside one of the many
.then()
methods. That's the only way to be sure.
You can, of course, use async
/await
—but that's just syntactic sugar that the JS engine turns into a promise…but that's a topic for another time :p
Another thing I caught, the resolve and reject functions only take regular values right?Yes and now, resolve/reject can take any value—but all values are "regular", that's one of JS's strengths! Functions are "regular" values. Regex, numbers, object, sets, etc are all "regular" values. The only way that JS discriminates values is if they're copy-by-reference or copy-by-value. Again, a topic for another time.
So is .then used to create another promise with the data the first promise returned?Yes,
.then()
, .catch()
and .finally()
all "wrap" their value in a new promise. That's how they're able to be chained.
And you’d use resolve for just either a message or a function that doesn’t use the data or that you want to run anyway when it’s done or something?Not really, no.
resolve
and reject
are used to pass on the value to the appropriate handler: .then()
on a resolution and .catch()
on a rejection. Resolve/reject just starts the ball rolling, but it's the further .then()
calls that actually do something with the value returned. Otherwise the value just disappears and does nothing.
i was just thinking, if promises are mostly used to retrieve info from another source, most functions/methods that allow for that such as fetch already return promises, so is there really a need to write them fresh yourself when you can just chain on a .then to fetch for example?Of course there are reasons to do it yourself! Think of making an API wrapper. Instead of needing to have the user hand-craft the
fetch()
call every time you have a class that does the boring stuff for you, and the user chains .then()
on to it to access the data from the API call. Or if you're writing a server, accessing the file system (reading/writing files) is asynchronous so you'd use promises there. Or if you wanted to do a lot of processing but didn't want it to all be done at once and freeze the main thread, you could make a queue out of promises. There are a lot of reasons you'd make your own.
gosh everything is very complex with js hahaAnd you've only begun to scratch the surface!
Would you like to know more?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
MDN Web Docs
Promise - JavaScript | MDN
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
that's not the only issue of storing a promise in a variable. if you store the result of a
.then
and then do var.then(); var.then();
, it isnt a chain and the value wont be passed from one to the other .then
, which is confusing
all the .then
will have the original value from when the variable was created
this shows the issue of storing a promise and not using a chain of .then
you would expect the last one to show 6, but since it is a different .then from a different place, it makes a different chainthis is what is happening
sorry the scuffed photo, but i'm at work
Right, once you break out of the chain you're no longer "passing" the promise value, you're just using an already-resolved Promise…which as you show, does nothing
and just confuses stuff
and has surprising side effects too
Yeah, well, that's JS for ya 🤷
yup, which is why i recommend to never put a promise in a variable
just use the chained methods and be happy
The only reason I can ever see putting a promise in a variable is when partially applying some args. But if you're dealing with the raw promise…never store it. You're not gonna use it again so it's just wasted memory.
yup, and if the return value is something big (like a blob), then it is even worse
because that has to stay in memory forever
Promises are a one-shot thing. Like plastic bags from the grocery store. Get your shit home and throw it out lol
yup, i couldnt agree more
And I gather that’s because you’re not chaining a new
.then
on to the one in the variable, you’re chaining it as though it’s the first, hence why it inherits that value from it (undefined) and not from any others you’ve done?
Ah okay I see, so with the resolve and reject values, you just pass in any variable or variables that’s useful or that you need in the .then function?no, it isnt chaining at all, so, the value isnt passed
if it was chained, then the value would pass until the end
You can only pass in one value to the resolve/reject functions. If you need to pass in multiple values then you'll have to wrap them in an object, array, etc and pass that one container value to the next step in the sequence
Ah okay, so logic wise, so it’s essentially the main value you receive that you pass on?
ohh okay