Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
310 views
in Technique[技术] by (71.8m points)

node.js - Promise.all and .map returning null

const returnPostData = async (req, res, initialPostsQueryArray) => {
    const promises = initialPostsQueryArray.map((post) => {

        let postObject;

        voteCount = sumValues(post.voting_options);
        pool.query('SELECT voting_option FROM votes WHERE user_id = $1 AND post_id = $2', 
            [req.user.userId, post.post_id], 
            (error, results) => {
                if (error) {
                    console.log(error);
                    return res.json({'Error': error.detail});
                }
                userVoteOption = results.rows[0].voting_option;
        });
        postObject.voteCount = voteCount;
        postObject.userVoteOption = userVoteOption;
        return postObject;
    });

    return Promise.all(promises).then(postData => {
        return res.json(postData);
    })
}

I'm trying to return an array of the postObjects for each post. For some reason it keeps on printing null for these objects because the return res.json is somehow running before the promises are even done. Any help is appreciated.

I had this problem before and used the same code, but it didn't work for this one for some reason.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Multiple problems:

  • You return postObject before userVoteOption is assigned
  • You don't actually use promises with node-postgres
  • …and therefore the return value of the map callback is not a promise
  • You never initialse postObject
  • You marked your function as async but never use await
  • You handle each error in the loop individually (which leads to res.json being called multiple times in case of multiple errors)

To fix these, use

async function returnPostData(req, res, initialPostsQueryArray) {
    try {
        const promises = initialPostsQueryArray.map(async (post) => {
            const voteCount = sumValues(post.voting_options);
            const results = await pool.query(
                'SELECT voting_option FROM votes WHERE user_id = $1 AND post_id = $2', 
                [req.user.userId, post.post_id]
            );
            const userVoteOption = results.rows[0].voting_option;
            const postObject = { voteCount, userVoteOption };
            return postObject;
        });
        const postData = await Promise.all(promises);
        res.json(postData);
    } catch(error) {
        console.log(error);
        res.json({'Error': error.detail});
    }
}

In addition, you actually shouldn't use a loop at all here. Just query multiple rows from postgres at once! Using this approach to supply the ids:

async function returnPostData(req, res, initialPostsQueryArray) {
    try {
        const voteCounts = new Map();
        const ids = [];
        for (const post of initialPostsQueryArray) {
            ids.push(post.post_id);
            voteCounts.set(post.post_id, sumValues(post.voting_options));
        }
        const {rows} = await pool.query(
            'SELECT post_id, voting_option FROM votes WHERE user_id = $1 AND post_id = ANY($2::int[])', 
            [req.user.userId, ids]
        );
        const postData = rows.map(row => {
            const postObject = {
                voteCount: voteCounts.get(row.post_id),
                userVoteOption: row.voting_option,
            };
            return postObject;
        });
        const postData = await Promise.all(promises);
        res.json(postData);
    } catch(error) {
        console.log(error);
        res.json({'Error': error.detail});
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...