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
Jochem
Jochem5d ago
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...
const prom = fetch(...);
prom.then();
const prom = fetch(...);
prom.then();
is exactly the same as
fetch(...).then();
fetch(...).then();
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
ἔρως
ἔρως5d ago
be EXTREMELY careful when saving a promise to a variable when you do .then(), you are creating a new promise
snxxwyy
snxxwyyOP5d ago
Ah okay that clears it up, thanks. What could mess up when you save it in a variable?
ἔρως
ἔρως5d ago
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 methods
snxxwyy
snxxwyyOP5d ago
Hm okay, that’s strange
ἔρως
ἔρως5d ago
it is weird as hell
snxxwyy
snxxwyyOP5d ago
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?
ἔρως
ἔρως5d ago
no, they take anything
snxxwyy
snxxwyyOP5d ago
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?
ἔρως
ἔρως5d ago
what do you mean?
snxxwyy
snxxwyyOP5d ago
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?
ἔρως
ἔρως5d ago
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 done
snxxwyy
snxxwyyOP5d ago
So it’s used to pass the data returned by the original promise around so you can do something with it in the .then block?
ἔρως
ἔρως5d ago
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!"
snxxwyy
snxxwyyOP5d ago
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?
ἔρως
ἔρως5d ago
no, it's the data passed to the resolve argument
snxxwyy
snxxwyyOP5d ago
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?
ἔρως
ἔρως5d ago
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
snxxwyy
snxxwyyOP5d ago
Ahh okay that and the example in the link makes sense now. I appreciate you explaining that.
ἔρως
ἔρως5d ago
you're welcome
snxxwyy
snxxwyyOP5d ago
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
Jochem
Jochem5d ago
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
ἔρως
ἔρως5d ago
or jquery $('div').first().text('hi!').css({color: 'red'}).hide().fadeIn('fast');
snxxwyy
snxxwyyOP5d ago
ohh okay i see, thanks
ἔρως
ἔρως5d ago
you can implement it really easily just make a class that returns this in it's methods
snxxwyy
snxxwyyOP4d ago
ah 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?
ἔρως
ἔρως4d ago
it will throw an error saying blah blah blah is not a function
Jochem
Jochem4d ago
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 do
snxxwyy
snxxwyyOP4d ago
ah okay i see, i see
ἔρως
ἔρως4d ago
depends on what you return
No description
snxxwyy
snxxwyyOP4d ago
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?
ἔρως
ἔρως4d ago
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
snxxwyy
snxxwyyOP4d ago
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?
ἔρως
ἔρως4d ago
you can do anything
snxxwyy
snxxwyyOP4d ago
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?
const number = 5;

console.log(number.toString());
const number = 5;

console.log(number.toString());
ἔρως
ἔρως4d ago
that's an internal function
snxxwyy
snxxwyyOP4d ago
so assigning a variable is actually a function with a return of the variable value?
ἔρως
ἔρως4d ago
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
snxxwyy
snxxwyyOP4d ago
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?
ἔρως
ἔρως4d ago
no, it doesn't return anything however, it is converted to an instance of a number object
snxxwyy
snxxwyyOP4d ago
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?
ἔρως
ἔρως4d ago
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
snxxwyy
snxxwyyOP4d ago
ah okay, but the scalar can include methods?
ἔρως
ἔρως4d ago
no it is internally converted to an object, during execution
snxxwyy
snxxwyyOP4d ago
ahh okay gosh everything is very complex with js haha
13eck
13eck4d ago
Ok, I'm gonna give this a try.
1) how does the promise object pass in the values to the resolve and reject parameters
You pass them in yourself within the Promise constructor.
new Promise( (resolve, reject) => {
if /* do work here is successful*/
resolve(dataFromAsyncWork);
else reject(new Error("Async work failed, time to cry");
});
new Promise( (resolve, reject) => {
if /* do work here is successful*/
resolve(dataFromAsyncWork);
else reject(new Error("Async work failed, time to cry");
});
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 fetch() method of the Window interface starts the process of fetching a resource from the network, returning a promise that is fulfilled once the response is available.
–MDN docs on 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 haha
And you've only begun to scratch the surface!
13eck
13eck4d ago
MDN Web Docs
Promise - JavaScript | MDN
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
ἔρως
ἔρως4d ago
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
const p = new Promise((resolve, reject) => resolve(5));

let x = p.then(val => console.log(val)); // shows 5, returns undefined

x.then(val => console.log(val)) // shows undefined - returned value from p.then

x.then(_ => 6) // returns 6
.then(val => console.log(val)); // shows 6

x.then(val => console.log(val)); // shows undefined - returned value from p.then
const p = new Promise((resolve, reject) => resolve(5));

let x = p.then(val => console.log(val)); // shows 5, returns undefined

x.then(val => console.log(val)) // shows undefined - returned value from p.then

x.then(_ => 6) // returns 6
.then(val => console.log(val)); // shows 6

x.then(val => console.log(val)); // shows undefined - returned value from p.then
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 chain
ἔρως
ἔρως4d ago
this is what is happening
No description
ἔρως
ἔρως4d ago
sorry the scuffed photo, but i'm at work
13eck
13eck4d ago
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
ἔρως
ἔρως4d ago
and just confuses stuff and has surprising side effects too
13eck
13eck4d ago
Yeah, well, that's JS for ya 🤷
ἔρως
ἔρως4d ago
yup, which is why i recommend to never put a promise in a variable just use the chained methods and be happy
13eck
13eck4d ago
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.
ἔρως
ἔρως4d ago
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
13eck
13eck4d ago
Promises are a one-shot thing. Like plastic bags from the grocery store. Get your shit home and throw it out lol
ἔρως
ἔρως4d ago
yup, i couldnt agree more
snxxwyy
snxxwyyOP4d ago
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?
ἔρως
ἔρως4d ago
no, it isnt chaining at all, so, the value isnt passed if it was chained, then the value would pass until the end
13eck
13eck4d ago
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
snxxwyy
snxxwyyOP4d ago
Ah okay, so logic wise, so it’s essentially the main value you receive that you pass on? ohh okay

Did you find this page helpful?