1

I'm trying to store in a variable ('randomColor') a random color from fetched colors, so that I can use it in my application. Whenever I log it in the console, it shows it is undefined. Logging the color directly from the fetch:

.then(color => console.log(color))

has been successful, since the console shows a random color.

I also tried fetching all the colors and getting a random color from them, but the same issue.

var randomColor;

globals = {
    currentColor: randomColor
};
fetch('https://raw.githubusercontent.com/bahamas10/css-color-names/master/css-color-names.json')
    .then(res => res.json())
    .then(obj => Object.keys(obj))
    .then(keys => keys[Math.floor(Math.random() * keys.length)])
    .then(color => randomColor = color);

What to do?

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
  • Make sure you only use `randomColor` inside `.then`, or in function that you call from inside a `.then`. I suspect you're trying to use it outside, which means you're using it before it's been assigned a value. – Paul Aug 13 '19 at 19:02
  • 3
    Please see [How do I return the response from an aynchronous call](https://stackoverflow.com/q/14220321/438992), which this duplicates. – Dave Newton Aug 13 '19 at 19:03
  • 1
    Why chain so many `.then`s for simple non-asynchronous methods? The final three `.then` expressions could just be one: `.then(obj => { let keys = Object.keys(obj); let color = keys[Math.floor(Math.random() * keys.length)]; randomColor = color; });` That said, I imagine Paulpro is right - it sounds like you're trying to use the color somewhere else. – Tyler Roper Aug 13 '19 at 19:09
  • @TylerRoper Because I was not on a machine on which it was easy to do when I wrote that. – Dave Newton Aug 13 '19 at 19:30

3 Answers3

0

Let's examine your code step by step

var randomColor;

globals = {
    currentColor: randomColor
};

You've created a variable randomColor which is currently undefined and passed it to a property of globals object. So in globals you have

globals = {
    currentColor: undefined
};

After that you make an asynchromous call

fetch('https://raw.githubusercontent.com/bahamas10/css-color-names/master/css-color-names.json')
    .then(res => res.json())
    .then(obj => Object.keys(obj))
    .then(keys => keys[Math.floor(Math.random() * keys.length)])
    .then(color => randomColor = color);

All the code is absolutelly correct and after the request is completed you get some random color in your randomColor variable. However, as long as primitives are passed by reference (like objects) your globals.currentColor still remains to be undefined.

You can rewrite your code as follows:

fetch('https://raw.githubusercontent.com/bahamas10/css-color-names/master/css-color-names.json')
    .then(res => res.json())
    .then(obj => Object.keys(obj))
    .then(keys => keys[Math.floor(Math.random() * keys.length)])
    .then(color => {
        // Here you can update all the required data
        randomColor = color;
        globals.currentColor = color;
        console.log(randomColor, globals);
     });
Sergey Mell
  • 7,780
  • 1
  • 26
  • 50
0

Because of the asynchronous nature of the promise you are invoking, it may be the case where you console.log(randomColor) the promise is not yet fulfilled and the value of randomColor remains undefined. randomColor only becomes the value you want it to become at the end of the promise chain .then(color => randomColor = color);. When you fire the promise any following synchronous code will run to completion before your promise is resolved!

Dan Starns
  • 3,765
  • 1
  • 10
  • 28
0

You can do something like this :

const randomColor = null;

await fetch('https://raw.githubusercontent.com/bahamas10/css-color-names/master/css-color-names.json')
  .then(res => 
  {
    const keys  = Object.keys(res.json());
    randomColor  = keys[Math.floor(Math.random() * keys.length)];
  })
  .catch(e => {
    console.log(e);
  });

console.log(randomColor);
Shim-Sao
  • 2,026
  • 2
  • 18
  • 23