logan9997
logan9997

Reputation: 73

JS functions giving inconsistent outputs in console

As someone who is still very new to JS i am struggling to understand why some of the functions and code i write give inconsistent outputs inside the console. For example the output of an array will contain 4 items on one refresh of the webpage, then contain 8 items on the next refresh. Why might this happen?

Example of this:

function biggestChanges(idsList) {
var listOfChanges = []
for (let i = 0; i < 16; i++) {
    fetch(`jsonFiles\\${idsList[i]}.json`)
    .then(response => response.json())
    .then(data => {
        //get data from JSON file
        var priceCurrentNEW = data.JSONdata[data.JSONdata.length - 1].prices[0]
        var priceDayBeforeNEW = data.JSONdata[data.JSONdata.length - 2].prices[0]
        var priceCurrentUSED = data.JSONdata[data.JSONdata.length - 1].prices[1]
        var priceDayBeforeUSED = data.JSONdata[data.JSONdata.length - 2].prices[1]

        var changeNEW = priceCurrentNEW / priceDayBeforeNEW * 100 -100 
        var changeUSED = priceCurrentUSED / priceDayBeforeUSED * 100 - 100
        var averageChange = (changeNEW + changeUSED) / 2
        averageChange = averageChange.toFixed(2)
    
        subList = [idsList[i], averageChange]
        listOfChanges.push(subList)

        //run on last iteration.
        if (i == 15) {
            var orderedList = []
            var originalLength = listOfChanges.length
            for (var x = 0; x < 16; x++) {
                var max = listOfChanges[0][1]
                var index = 0
                // -k on range as on each iteration the length of the list decreases by 1
                for (var k = 0; k < 16-k; k++) {                        
                    if (listOfChanges[k][1] > max) {
                        max = listOfChanges[k][1]
                        index = k
                    }        
                }
                orderedList.push(listOfChanges[index]) 
                listOfChanges.splice(index, 1) 
            }
                console.log(orderedList, "orderedlist")
                for (var l = 0; l < orderedList.length; l++){
                document.getElementById(`change-${orderedList[l][0]}`).innerHTML = "change: £" + orderedList[l][1]
                }
        }
    })  
}

}
function finalBiggestChanges() {
    fetch("JSONitemIDsList.json")
    .then(response => response.json())
    .then(data => {
        biggestChanges(data.ids)
    })
}

finalBiggestChanges()

Example output 1Example output 2

Upvotes: 0

Views: 31

Answers (1)

Bergi
Bergi

Reputation: 665130

You've got a race condition. //run on last iteration. actually runs during the callback of the last iteration to start the fetch(`jsonFiles\\${idsList[i]}.json`) call, but not necessarily when the last http response arrived.

You can mitigate this by doing if (listOfChanges.length == 16) (i.e. when the 16th response was added to the array) instead of if (i == 15), but really the proper solution is to use Promise.all instead:

function loadChange(id) {
    return fetch(`jsonFiles\\${idsList[i]}.json`)
    .then(response => response.json())
    .then(data => {
        //get data from JSON file
        var priceCurrentNEW = data.JSONdata[data.JSONdata.length - 1].prices[0]
        var priceDayBeforeNEW = data.JSONdata[data.JSONdata.length - 2].prices[0]
        var priceCurrentUSED = data.JSONdata[data.JSONdata.length - 1].prices[1]
        var priceDayBeforeUSED = data.JSONdata[data.JSONdata.length - 2].prices[1]

        var changeNEW = priceCurrentNEW / priceDayBeforeNEW * 100 -100 
        var changeUSED = priceCurrentUSED / priceDayBeforeUSED * 100 - 100
        var averageChange = (changeNEW + changeUSED) / 2
        averageChange = averageChange.toFixed(2)
    
        return [id, averageChange]
    });
}


function finalBiggestChanges() {
    return fetch("JSONitemIDsList.json")
    .then(response => response.json())
    .then(data => {
        return Promise.all(data.ids.slice(0, 16).map(loadChange));
    })
    .then(listOfChanges => {
        listOfChanges.sort((a, b) => b[1] - a[1]); // largest first
        console.log(listOfChanges, "orderedlist")
        for (const change of listOfChanges) {
            document.getElementById(`change-${change[0]}`).innerHTML = "change: £" + change[1]
        }
    });
}

finalBiggestChanges().catch(console.error);

Upvotes: 1

Related Questions