2

in one of youtube tutorial videos about promises I found following code:

let cleanRoom = function() {
  return new Promise((resolve, reject) => {
    resolve();
  });
};

let removeGarbage = function() {
  return new Promise((resolve, reject) => {
    resolve();
  });
};

let winIcecream = function() {
  return new Promise((resolve, reject) => {
    resolve();
  });
};

cleanRoom().then(function(){
  return removeGarbage();
}).then(function() {
  return winIcecream();
}).then(function() {
  console.log('finished');
})

Why the promises aren't chained like that the every .then word is after the previous promise? I mean, why for example .then is not immediately after removeGarbage() but it is after the cleanRoom().then(), how is it happening that the winIcecream() will run after resolving the removeGarbage promise? Also do I need to type return declaring every promise like in the code above? If yes, why do I need to do so?

joar
  • 15,077
  • 1
  • 29
  • 54
bartekw2213
  • 81
  • 1
  • 7
  • This is a rather bizarre example. Are the async functions supposed to return a value? If so, you might want to create a variable and assign it to the chain of promises. THat way you will have the value – CodeTrooper Jan 05 '20 at 09:58
  • 1
    Actually [we can](https://stackoverflow.com/a/22000931/1048572), and [we sometimes do](https://stackoverflow.com/a/28250687/1048572), we just try to avoid it where we don't need it (as otherwise it leads to a pyramid of doom). – Bergi Jan 05 '20 at 09:59

3 Answers3

3

Your initial questions may be answered by rewriting things to variable assignments.

I'm using arrow function syntax to implicitly return the new expression here; if you're using regular functions, then yes, you do have to return the new chained promise if you want to run them in sequence.

const roomCleanedPromise = cleanRoom();
const roomCleanedAndGarbageTakenOutPromise = roomCleanedPromise.then(() => removeGarbage());
const roomCleanedAndGarbageTakenOutAndIcecreamWonPromise = roomCleanedAndGarbageTakenOutPromise.then(() => winIcecream());
const finishedPromise = roomCleanedAndGarbageTakenOutAndIcecreamWonPromise.then(() => console.log('finished'));

However things are easier written using the more modern async/await syntax - the YouTube tutorial you mention is a little outdated, perhaps.


async function cleanRoom() {
  console.log('Cleaning room.');
  // this could do other async things or just take a while
  return {room: 'clean'};  // just to demonstrate a return value
}


async function removeGarbage() {
  console.log('Removing garbage.');
  // this could do other async things or just take a while
  return {garbage: 'removed'};
}

// third function elided for brevity

async function doAllTheThings() {
  const roomStatus = await cleanRoom();
  const garbageStatus = await removeGarbage();
  console.log('finished');
}
AKX
  • 152,115
  • 15
  • 115
  • 172
2

The purpose of using a fulfillment handler (the functions passed to then in your example) is to wait for the promise to be fulfilled and then, at that point, do something else.

The goal of that code (apparently) is to wait until the cleanRoom promise is fulfilled, then start the removeGarbage process, and then when that is fulfilled, start the winIcecream process. It's also worth noting that if cleanRoom's promise was rejected instead of being fulfilled, removeGarbage wouldn't happen at all, because it's in a fulfillment handler, not a rejection handler.

If you did this instead:

cleanRoom().then(function() { /*...*/ });
removeGarbage().then(function() { /*...*/ });
winIcecream().then(function() { /*...*/ });

...all three processes would be started immediately and run in parallel (to the extent whatever async process they're modelling can run in parallel with other JavaScript code). There'd be no coordination between them at all.

...how is it happening that the winIcecream() will run after resolving the removeGarbage promise...

then, catch, and finally create and return new promises. Those promises are fulfilled or rejected based on what happens to the promise they were called on and what happens in or is returned by their handler. So for example:

doThis()
.then(function() { return doThat(); })
.then(function() { console.log("done"); });

Let's call the promise from doThis() "Promise A". Calling then on it creates a new promise ("Promise B"), that will either be rejected (if Promise A is rejected) or will call its handler if Promise A is fulfilled. Promise B is resolved to whatever that handler returns. In the code above, suppose Promise A is fulfilled and doThat() returns a promise ("Promise C"). Now, Promise B is resolved to Promise C — whatever happens to Promise C is what will happen to Promise B. If Promise C is fulfilled, Promise B is fulfilled, and the second handler with the console.log is called.

The MDN article on using promises may be helpful.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

Your suggestion / thinking I mean, why for example .then is not immediately after removeGarbage() but it is after the cleanRoom().then() is wrong. Each promise ( .then ) is not execute immediately.

You can take a look at your example ( little edited by me )

const cleanRoom = () => new Promise((resolve, reject) => {
  resolve();
});

const removeGarbage = () => new Promise((resolve, reject) => {
  resolve();
});

const winIcecream = () => new Promise((resolve, reject) => {
  resolve();
})

cleanRoom().then(function(){
  console.log('second');
  return removeGarbage();
}).then(function() {
  return winIcecream();
}).then(function() {
  console.log('finished');
})

console.log('first');

You should read more how the event loop works.