CyrisXD CyrisXD - 4 months ago 7
Node.js Question

Array storing random order each time through loop

I am trying to store multiple objects into an array, to then be rendered out in order.

My process is as follows:

app.js

var allOdds = [];
var count = 0;
// =====================================
/* Database Config and Error Handling */
// =====================================
tools.databaseConnect();
// Get option number from database
connection.query("SELECT * FROM OptionNumbers ORDER BY id", function(err, rows, fields) {
console.log("CALL FROM DATABASE");
var totalRows = rows.length;

rows.forEach(function(key, value) {

request('http://url/for/data' + key.number, function(error, response, body) {

if (!error && response.statusCode == 200) {

// Parse XML response
if (body.includes('selection')) {
var odds1 = $(body).find('selection').eq(0).attr('odds');
var odds2 = $(body).find('selection').eq(1).attr('odds');

var obj = {
team1odds: odds1,
team2odds: odds2
};
allOdds.push(obj);

} else {
var obj = {
team1odds: 0.00,
team2odds: 0.00
};
allOdds.push(obj);
}



if ((count + 1) === totalRows) {
// Render index with results
res.render('index', {
title: 'Best Bets',
time: tools.DisplayCityTime('+12'),
completeOdds: allOdds
});
}
count++;

} //end if || Nothing Odds Found

});
});

});


The order of "key.number" from the database is consistent, but the order of the process storing the objects seems random?

<% completeOdds.forEach(function(sortedOdds) { %>
<div class="rowContainer" style="width:500px; padding:20px; margin-bottom:20px; border:2px solid grey;">
<p style="width:50%; float:left;">
<%= sortedOdds.team1odds %>
</p>
<p style="width:50%; float:left;">
<%= sortedOdds.team2odds %>
</p>
<div style="clear:both; width:100%;"></div>
</div>
<% }); %>


Rendered result order is random such as below example
1 - 3 - 2, 3 - 1 - 2, etc...

I would like to retrieve from the API. Then store each into an array, to be rendered on the page in the order they were retrieved.

Answer

The problem is you cannot be sure which request is fulfilled in what order. Imagine loading three separate web pages one after the other in separate tabs. There is no guarantee that they will finish loading in the order you opened them.

Using javascript promises is one way to address this. I create an empty array called promises. For each request made, you create a new Promise. This promise will be "resolved" or "rejected" based on the result of request(...). This promise is now pushed to the array promises in the order you want.

Once all of the promises in the array have been resolved, Promise.all(promises) will be resolved. Its resolved value will be an array containing the resolved values from the previous requests.

var promises = [];

rows.forEach(function (key, value) {
    var p = new Promise(function (resolve, reject) {
        request("...", function (error, response, body) {
            if (error) {
                //handle error
            } else {
                resolve(body);
            }
        });
    });
    promises.push(p);
});

//this function will not be called until all requests have returned
Promise.all(promises).then(function (resp) {
    //these will be in order
    console.log(resp[0]);
    console.log(resp[1]);
    console.log(resp[2]);
});