Learning Javascript promises, just curious

Below is a piece of meaningless code to test something out that I’m unsure of.

const delayedColorChange = (newColor, delay) => {
    return new Promise((resolved, rejected) => {
        setTimeout(() => {
            document.body.style.backgroundColor = newColor
            resolved();
        }, delay)
    })
}
 
async function rainbow() {
    delayedColorChange('red', 1000)
}

Okay so both delayedColorChange('red', 1000) and async function rainbow() both return promises. When I run rainbow() from the console I see it’s promise is returned but what happens to the promise from delayedColorChange('red', 1000) does it just hang there unused?

Just looking at it quickly, wouldn’t rainbow return the promise from delayedColorChange? My mind is a little foggy at the moment, but I think that is what I would expect to see.

I think it just fades away into the sunset since you are not capturing the returned promise in rainbow(). One caveat to this is that you are always resolving the promise created in delayedColorChange() so there is really no harm done if you don’t handle it in rainbow(). Now, if it were possible for that promise to be rejected then you would get an UnhandledPromiseRejection error if it was rejected for some reason (at least in node) because rejected promises need to be handled.

@kevinSmith, my testing is showing that rainbow() would return a promise with the value of undefined in this case because it doesn’t have a return statement. If you did

return delayedColorChange('red', 1000)

then the promise it returns would have the value returned in the promise from delayedColorChange. In this case that would be undefined but when I added a string to resolved() it was returned by rainbow().

Of course I could be a little fuzzy on this too. Promises always seem to throw me for a loop and I find I have to re-educate myself on them every six months or so :slight_smile:

Another way to think about this is consider how this code would work if you just used callbacks rather than async/await and or Promises.

At the end of the day async/await is “syntax sugar” on Promises and Promises themselves are “syntax sugar” around callbacks that all focus around the concept of JS “combing back to a call” or a “call-back”.

So going back to the code, this snippet:

async function rainbow() {
    delayedColorChange('red', 1000)
}
console.log(rainbow());

would work the same as:

function rainbow() {
    delayedColorChange('red', 1000)
   return Promise.resolve(); 
}
console.log(rainbow());

this also is the same:

function rainbow() {
   return Promise.resolve(); 
}
console.log(rainbow());

Now at this point, you might be asking “but wait, what about my delayedColorChange when is it executed?” It is executed as you called it, but that doesn’t mean your code cares about what it returns/does after its called. Your code just keeps marching along, and doesn’t care about “getting called back” from what is returned from delayedColorChange

If you noticed, there are functions within delayedColorChange that are called “later”, IE the one function you passed into setTimeout will be “called back”, so the color is changed at the right time.

The idea that JavaScript can be “called back” all over the place, out of order is one of the reasons why its fast, even though it can only be in 1 place at 1 time.

So just to finalize, if you do care about when delayedColorChange is “finished” here’s the three ways to do it:
callback

const delayedColorChange = (newColor, delay, doneFn) => {
        setTimeout(() => {
            document.body.style.backgroundColor = newColor
            doneFn();
        }, delay)
    })
}
 
async function rainbow() {
    delayedColorChange('red', 1000, () => console.log('DONE!'))
}

Promise based (this is similar to your except we will remove async/await for simplicity

const delayedColorChange = (newColor, delay) => {
  return new Promise((resolve) =>
    setTimeout(() => {
      document.body.style.backgroundColor = newColor;
      resolve();
    }, delay)
  );
};

function rainbow() {
  delayedColorChange("red", 1000).then(() => console.log("DONE!"));
}

async/await based

const delayedColorChange = (newColor, delay) => {
  // **note** you still need a Promise to "wrap" the callback of setTimeout
  return new Promise((resolve) =>
    setTimeout(() => {
      document.body.style.backgroundColor = newColor;
      resolve();
    }, delay)
  );
};

async function rainbow() {
  await delayedColorChange("red", 1000);
  console.log("DONE!");
}

note the original snippet posted essentially says “do delayedColorChange()” then immediately leaves the function not caring about the result. This doesn’t mean delayedColorChange doesn’t happen/is fired, its just you don’t care about what it resolves to.

1 Like

I tried what you said (see below) and that made sense i.e.

  • The promise fading away into the sunset makes sense.
  • Giving resolved a string and returning the output from delayedColorChange() in rainbow().
const delayedColorChange = (newColor, delay) => {
    return new Promise((resolved, rejected) =>
        setTimeout(() => {
            document.body.style.backgroundColor = newColor
            resolved("Hello from delayedColorChange");
        }, delay)
    )
}

async function rainbow() {
    return delayedColorChange('red', 1000)
}

console.log(rainbow())```

Putting

return Promise().resolve();

didn’t work for me at all

Uncaught TypeError: undefined is not a promise
    at Promise (<anonymous>)
    at rainbow (app.js:12)
    at app.js:15

But not to worry.

In the nugget below how are you resolving resolve()?

const delayedColorChange = (newColor, delay) => {
        setTimeout(() => {
            document.body.style.backgroundColor = newColor
            resolve();
        }, delay)
    })
}
 
function rainbow() {
    delayedColorChange('red', 1000).then(() => console.log('DONE!')
}

I was going to add another question here regarding this code but have decided to put it in another thread. I’m bowled over by the response and didn’t even expect to get an answer. I’m new to promises and it looks like I’ll prolly have a better understanding only after using them in anger but before moving on now I’d like to try and understand as much as poss.

Thanks again to everyone :slight_smile:

Whoops sorry the correct syntax is:

Promise.resolve()

(resolve is a static method on Promise)

I’ll update my post a little more, I was editing the snippet as-is without double checking, sorry for any confusion it has caused. :slight_smile:

It took me some time before I felt like I really understood promises. I had to use them a lot in a few different scenarios and formats to really “get it”. I like the idea of “using them in anger” to figure them out. Such experience will help understand async/await later aswell :smiley:

I’m sure they’re fairly straightforward at the end of the day but right now I’m just not getting it and that’s the frustrating bit. Well I do to a degree but still lots to learn. Thanks again :slight_smile:

I have posted another question as I was beginning to have trouble following everyone’s response. It’s almost the same code wise but it may highlight why I’m having trouble getting to grips with the basics.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.