0

I am a JavaScript newbie and have a problem regarding an AJAX call to a local JSON file and afterwards accessing elements of the resulting data array. I fetch values called "number" from a local JSON file and put them in an array. My problem is: I can perfectly well log the whole array, but not single array values with "data[0]".

After a long search I am now pretty sure that it is an AJAX problem because I can log the element if I put the logging function into a setTimeout. I thought the async-await part would solve this, but apparently it does not. I have tried to use the "return new Promise((resolve, reject) => { ..." syntax in makeDataArray() instead, but it doesn't work either. I don't understand why the await-keyword does not wait "long enough" for the makeDataArray() function to finish. Can someone please explain this to me?

In case this is important: I am not allowed to use jQuery, which is why I use the asycn-await construct.

This is the JavaScript:

async function makeDataArray() {
        var myNumbers = new Array();
        fetch('../data/someNumbers.json')
            .then(response => response.json())
            .then(data => {
                data.forEach(element =>{
                    myNumbers.push(element.number);
            })
        })  
        return myNumbers;
}

async function printArrayElements(){
    let data = await makeDataArray();
    console.log(data); //works correctly
    console.log(data[0]); //undefined
    setTimeout(function(){ 
        console.log(data[0]);}, //works correctly
        3000);
}

printArrayElements();

This is the JSON file:

[{
    "number": 10
},
{
    "number": 20
},
{
    "number": 30
}
]
fransie
  • 67
  • 8
  • That is not supposed to work at all; your promise chain does not return anything and you do not even return the promise in `makeDataArray`. – H.B. Jun 24 '20 at 18:25
  • Thanks for pointing it out, the missing return statement was a copy-paste and edit afterwards mistake. I corrected it. – fransie Jun 24 '20 at 18:28
  • But doesn't the async keyword in front of a function automatically return a promise? At least I read that in this tutorial https://javascript.info/async-await – fransie Jun 24 '20 at 18:30
  • Yes, but if you have no return statement the promise will not yield your result. – H.B. Jun 24 '20 at 18:31
  • Your first log works only because [a peculiarity of the console](https://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays). You're printing the array reference, the array is populated later, so by the time you examine the object in the console, you are seeing is *current* state, not the state it was in when the log was made. The second log is *correct*, since at the time of printing, there is no data. The third one just happens to work after the array is populated. You should just use `return fetch()` in `makeDataArray()` – VLAZ Jun 24 '20 at 18:32
  • 1
    In your updated code you need to `await` the `fetch` to fix it, otherwise you return the empty `myNumbers` array directly. But i would not mix `then` and `async` like that. – H.B. Jun 24 '20 at 18:35
  • @VLAZ ah thank you, that makes more sense now! – fransie Jun 24 '20 at 18:36

2 Answers2

2

That looks quite wrong; this is what i would expect if you use then chains:

function makeDataArray() {
    return fetch('../data/someNumbers.json')
        .then(response => response.json())
        .then(data => data.map(x => x.number))
}

If you use chaining you need to return your result in the last then.

Using async/await:

async function makeDataArray() {
    const response = await fetch('../data/someNumbers.json');
    const json = await response.json();
    
    return json.map(x => x.number);
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
0

I am pretty sure that the code you have posted is not the code you get the console logs with. The makeDataArray function does not have any return statement, so it will return a Promise<void> - a promise that will resolve into nothing. You probably want to to something like:

async function makeDataArray() {
    const data = await fetch('../data/someNumbers.json')
    return await data.json();
}
Dimitri L.
  • 4,499
  • 1
  • 15
  • 19