Dbercules
Dbercules

Reputation: 719

Promise.all() returns undefined array of Promise <Pending>'s, despite similar solutions returning successful alternatives

I'm building a web app that allows users to view a dashboard of items, which in turn have individual sections (a, b, and c), which the dashboard will show as complete (o) or incomplete (x) as illustrated below. This allows the user to navigate directly to the page that has missing information, as all of an item's information is required to progress to the next stage.

Item | a | b | c | Next Stage?
------------------------------
abc  | x | o | x | No
def  | x | x | x | No
ghi  | o | o | o | Yes

Within each item (e.g. abc), it can have a number of sub-items which must all be completed for that item's a, b, or c section to be marked as complete. This has been achieved through a nested series of promises that update a 'completeness' variable whenever a sub-item is updated. However, the issue arises when attempting to transport the variable from the scope of sub-items (a's, b's, c's) to parent items (abc, def, ghi). I've previously used nested promises without implementation of async/await and as this is the final usage of a promise within the scope of this project, I'm hesitant to adopt a different way of solving this problem (but I'm not against it).

Current Implementation:

exports.loadDashboard = (req, res, next) => {
Item.find()
.where("user").equals(req.session.user)
.select()
.exec()
.then(docs => {
    const response = {
        items: docs.map(doc => {
            const aPromise = Feature.find().where("projectID").equals(doc._id).select("aComplete").exec();
            const bPromise = Feature.find().where("projectID").equals(doc._id).select("bComplete").exec();
            const cPromise = Feature.find().where("projectID").equals(doc._id).select("cComplete").exec();
            Promise.all([aPromise, bPromise, cPromise]).then(result => {
                return{
                    _id: doc._id,
                    user: doc.user,
                    aComplete: result[0],
                    bComplete: result[1],
                    cComplete: result[2]
                }
            // })
        }
    ),
    userSessionID: req.session.user   
    }
    if(req.session.user != null){
        console.log(response);
        res.render("dashboard", {response});
    }else{
        res.redirect("login");
    }
})
.catch(err=>{
    console.log(err);
    res.status(500).json({
        error: err
    });
});

}

...which grants a response of:

{  items: [ undefined, undefined, undefined ],
 userSessionID: '1' }

These undefined items are of type Promise <Pending>, and similar issues have been solved in similar manners, but this time I'm quite stuck. My question is, is it possible to solve this without delving into async/await, or should I bite the bullet, and if that's the case I'd be most grateful for any assistance provided.

Thanks for reading

Upvotes: 2

Views: 574

Answers (1)

BenSower
BenSower

Reputation: 1612

There is a lot going on here and if possible, switch to using async/await instead of using Promises, since this is one of the main reasons that makes your code rather hard to maintain. I believe you might just have to actually return the correct values.

Your .map function doesn't return anything, which might be the main reason, you're receiving [undefined, undefined, undefined].

exports.loadDashboard = (req, res, next) => {
// don't use "where", if you don't have to
Item.find({user: req.session.user)
.exec()
.then(docs => {
  const items = docs.map(doc => {
            const aPromise = Feature.find().where("projectID").equals(doc._id).select("aComplete").exec();
            const bPromise = Feature.find().where("projectID").equals(doc._id).select("bComplete").exec();
            const cPromise = Feature.find().where("projectID").equals(doc._id).select("cComplete").exec();
            // THIS IS WHERE I ADDED THE RETURN!
            return Promise.all([aPromise, bPromise, cPromise])
             .then(result => {
                return {
                    _id: doc._id,
                    user: doc.user,
                    aComplete: result[0],
                    bComplete: result[1],
                    cComplete: result[2]
                }
            }
       )})
  return Promise.all(items);
})
.then(items => {
    const response = {
       userSessionID: req.session.user,
       items
    };
    // also check if .user is undefined, the null check is then optional
    if(!req.session.user || req.session.user === null){
      return res.redirect("login");
    }
    console.log(response);
    return res.render("dashboard", {response});
}).catch(error => {
  console.log(error);
  res.status(500).json({error});
});

and see how it goes. I believe there might still be some issues, but that outline should make it easier for you to work with it.

Upvotes: 2

Related Questions