0

I'm working on a project where at one point, I run a series of promises and then push their results (in the .then() portion) to an array. The issue is that, although the promise itself is providing a result value, nothing is actually being pushed to the array itself. Below is the create function in my code where I'm using Promise.all() to run a series of processes on an array made of promises called newJoinsPromiseArray.

export const create = (req, res, next) => {
    const newJoinsPromiseArray = []; //This will be an array of the new joins that we are adding
    for (const worker of req.body.workers){
        const newJoinElement = new JoinTable(null, req.body.contact_id, worker.value) //We use value here since it's in the form that multi-select gave us
        newJoinElement.save()
        .then((result) => {
            newJoinsPromiseArray.push(JoinTable.findByID(result[0].insertId))
        })
        .catch(err => res.json({message: err}))
    }
    Promise.all(newJoinsPromiseArray).then((values) => {console.log(values)})
}

So whenever I console.log(newJoinsPromiseArray), it just prints []. I've tried this also by just running the JoinTable.findByID function on each element then pushing what it returns to the array, although I think that's the same thing.

Below are my functions for save and findByID:

save(){
        /* The purpose of this function is to save a new element to the database. */
        return db.execute(`INSERT INTO workercontacts (contact_id, worker_id) VALUES(?, ?)`, [this.contact_id, this.worker_id]);
    }

static findByID(element_id){
        // Will give us a specific element based on the id 
        return db.execute('SELECT * FROM workerContacts WHERE workerContacts.id = ?', [element_id]);
    }

I'm using a MySQL database which I don't think has anything to do with this issue but I thought I'd add that information just in case.

Edit:

Adding on to this, this was my new attempt at making this work, which it still didn't

 export const create = async (req, res, next) => {
        const newJoinsPromiseArray = []; //This will be an array of the new joins that we are adding
        for (const worker of req.body.workers){
            const newJoinElement = new JoinTable(null, req.body.contact_id, worker.value) //We use value here since it's in the form that multi-select gave us
            try{
                const savedResult = await newJoinElement.save();
                const joinElementByID = await JoinTable.findByID(savedResult[0].insertId);
                newJoinsPromiseArray.concat(joinElementByID);
            }
            catch (e){
                res.json({message: e})
            }
    }
    console.log(newJoinsPromiseArray)
}

I'm still lost unfortunately but thank you for all of your help thusfar.

zichyboy
  • 105
  • 2
  • 8
  • `then` executes after the cycle so use `await` instead of `then` to wait for `save` result. – Anatoly Sep 28 '22 at 19:03
  • because `newJoinElement.save()` is obviously async,and you are pushing into that array only in the `then` handler of the promise you are not awaiting in the loop. Thus, when you reach your `Promise.all` none of the `newJoinElement.save()` has yet executed, and thus the array is empty. – derpirscher Sep 28 '22 at 19:04
  • Does this answer your question? [How to access the value of a promise?](https://stackoverflow.com/questions/29516390/how-to-access-the-value-of-a-promise) – evolutionxbox Sep 28 '22 at 19:07
  • I'm very new to async await so sorry if my question seems stupid, but would I use the async on the findByID function or would I use it in the big create function? – zichyboy Sep 28 '22 at 19:20

2 Answers2

1

You should be pushing the Promises into the array.

newJoinsPromiseArray.push(newJoinElement.save().then(result => JoinTable.findByID(result[0].insertId));

Alternatively, you could make the function async and use await on each of the save operations in the loop.

Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • The return values are in a form that isn't exactly what I was hoping for. It's very close and, although it could work, the way to make it work would be a little all over the place (you'd have to do something like Promise.all(promiseArray... => [values[0]][0]. Not exactly that, but I feel like finding out how exactly to do it would be better spent understanding async). Thank you nonetheless! – zichyboy Sep 28 '22 at 19:24
  • @zichyboy What is the expected result? – Unmitigated Sep 28 '22 at 19:26
  • I realized it's a lot easier than I originally thought. I just had to map over them and then take the first element (Promise.all(newJoinsPromiseArray).then((values) => console.log(values.map(val => val[0])))) – zichyboy Sep 28 '22 at 19:37
0

I figured it out thanks to @Unmitigated! I just changed my create function to be this:

export const create = (req, res, next) => {
    const newJoinsPromiseArray = [];
    for (const worker of req.body.workers){
        const newJoinElement = new JoinTable(null, req.body.contact_id, worker.value) //We use value here since it's in the form that multi-select gave us
        newJoinsPromiseArray.push(newJoinElement.save().then(result => JoinTable.findByID(result[0].insertId)))
    }
    Promise.all(newJoinsPromiseArray).then((values) => res.json(values.map(val => val[0]).flat()))
}
zichyboy
  • 105
  • 2
  • 8