-1

I'm trying to fill an array of numbers after a http get request. I implemented a function that should return this array, but when I try to use it, it is empty. I tried to console.log the array inside the function and it is correctly filled with what I expected, but it appears to log after the execution of the function instead of during execution.

I don't understand how to wait until the function fills the array to use it properly, can you help me? Is it ok to use .then methods inside other .then?

Here is the code, that I simplified a bit to make it more understandable:

router.get('/newRail/:trainNumber', function (req, res) {
    railsAvailable(req.params.trainNumber).then(function (placing) {
        res.json(placing);
        // If you read placing at this moment it results empty
    });
});

function railsAvailable(trainNumber) {
    return Promise.resolve(findBadRail(trainNumber));
}

function findBadRail(trainNumber) {
    var badRail = [];
    getPlacingByTN(trainNumber).then(placing => {
        badRail.push(placing.rail);

        getAllPlacings().then(allPlacings => {
            allPlacings.forEach(function (p) {
                //some computation on the array here...
                // .....
                // .....
                badRail.push(p.rail);
            });
            console.log(badRail)
        });
    });
    return badRail;
}

function getPlacingByTN(trainNumber) {
    // getting from a mongoDb collection
    return CollectionDB.findOne({"trainNumberArr": {$eq: trainNumber}}, {});
}

function getAllPlacings() {
    // getting from a mongoDb collection
    return CollectionDB.find();
}
Davide
  • 1
  • 2
  • Try 'return railsAvailable(..)' in the get function – Oli Aug 19 '20 at 11:39
  • The key error here (among others) is that `findBadRail` is supposed to return the Promise chain, not the (empty) array. Also, that code doesn't look simplified at all, it actually looks convoluted. Returning a single DB results is way easier & shorter to achieve. –  Aug 19 '20 at 11:39
  • @Oli Nope, that's not it, express route callbacks don't need to return anything; they call `res.*` instead (see my comment) –  Aug 19 '20 at 11:40
  • @ChrisG I tried to return Promise.resolve(badRail); but anything changes, am I doing it wrong? The code seems convoluted because in the real one there are several checks that have to be done in the middle, but I think that it is not useful for the point of the question. This is why I removed it – Davide Aug 19 '20 at 11:52
  • I'm not sure what exactly your code is doing, but I guess it could profit from using `Promise.all()`; also using `.forEach` to fill an empty array usually means you can use `.map()` instead. Regardless of all that, whenever you want to call `.then()` on the result of a custom function, you need to make sure that function returns a *Promise*. –  Aug 19 '20 at 12:10
  • Here's example code that runs three async operations in a custom function and outputs the result: https://jsfiddle.net/8xyokqsh/ –  Aug 19 '20 at 12:16

1 Answers1

0

findBadRail will return most likely return before getPlacingByTN resolves... Have you tried using async/await?

async function findBadRail(trainNumber) {
    var badRail = [];
    const placing = await getPlacingByTN(trainNumber);
    badRail.push(placing.rail);
    const allPlacings = await getAllPlacings();
    allPlacings.forEach(p => badRail.push(p.rail);
    console.log(badRail);
    return badRail;  
}
Dev Yego
  • 539
  • 2
  • 12
  • No, how should I use them? – Davide Aug 19 '20 at 11:55
  • I would suggest so, you're trying to follow asynchronous code in a synchronous way.. Using `async/await` will help you stick with the synchronous mental model. – Dev Yego Aug 19 '20 at 11:57
  • I have edited the answer to include the changes you might want to make. – Dev Yego Aug 19 '20 at 12:37
  • Thank you! It works fine! Now I understand how to use async/await, I was trying without really getting the point, thank you. – Davide Aug 19 '20 at 12:48
  • Anytime, you should also be aware that `findBadRail` now returns a promise and you will have to `await` it or use promise chaining with `then`. – Dev Yego Aug 19 '20 at 12:54