繁体   English   中英

如何从Array.map()函数正确返回异步数据

[英]How to properly return async data from Array.map() function

我正在开发一个小型Web应用程序,以跟踪本地棋盘游戏小组的积分。 计分板将跟踪玩家参加的总比赛数,获得的总积分以及比赛的细目分类和每个派系中可获得的积分。

我目前正在碰壁,试图为/ players / withFactions /创建节点/ express端点,这将返回聚合的玩家数据以及每个派别的细分。

正如您将在所附的代码中看到的那样,逻辑正确地工作,并且数据在第一个console.log的位置正确。 该数据只是返回了,我将返回值记录在第二个控制台日志中,那里的数据似乎已更改。 突变的数据似乎总是采用第一个console.log位置中最后返回的元素的形式。 我希望这在审查代码时会更有意义。

我确信我的问题在于我如何处理所有异步,但是我无法找出解决方案。

我已经以多种不同的方式攻击了这个问题:回调,承诺,异步/等待。 所有结果都相同。 在返回前端之前,数据似乎在我身上发生了变化。

router.get('/withFactions', async (req, res) => {

    const { rows: players }  = await db.query('SELECT * FROM players');
    const { rows: factions }  = await db.query('SELECT * FROM factions');

    const playerResults = await Promise.all(players.map( async (player) => {
        await db.query('SELECT * FROM gameentry WHERE player_id = $1', [player.id]).then((result) => {
            const gameEntries = result.rows;
            const factionTotals = factions.map((faction) => {
                const factionEntries = gameEntries.filter(game => game.faction_id === faction.id)
                faction.totalPoints = factionEntries.reduce((acc, curr) => {
                    return acc + curr.points;
                }, 0)
                return faction;

            })
            player.factionTotals = factionTotals;
        })  
        player.factionTotals.forEach(element => console.log(element.totalPoints)) 

// total scores are recording correctly here   4,0,0   5,0,3   0,5,0 (from DB data)

        return await player;
    }))

    await playerResults.forEach(player => player.factionTotals.forEach(element => console.log(element.totalPoints))); 

// total scores are wrong here. Each set is 0,5,0. Seems to just replicate the last set from within the promise

    res.send(await playerResults);
})

注意:唯一不正确的数据是player.factionTotals,其余的播放器数据仍然准确。

我敢肯定那里还有更多的等待。 我一直在研究这个问题太久了。 希望我能对此有所帮助。

正如Jaromanda X所指出的那样 ,问题在于您需要为每个玩家修改factions ,因此只有最后一次修改会“停留”。

通常,我建议使用map时不要有副作用,而只返回新对象或未修改的对象。 为此,您应该可以将代码修改为以下形式:

router.get('/withFactions', async (req, res) =>
{
    const { rows: players } = await db.query('SELECT * FROM players');
    const { rows: factions } = await db.query('SELECT * FROM factions');

    const playerResults = await Promise.all(players.map(async player =>
    {
        const { rows: gameEntries } = await db.query('SELECT * FROM gameentry WHERE player_id = $1', [player.id]);

        const factionTotals = factions.map(faction =>
        {
            const factionEntries = gameEntries.filter(game => game.faction_id === faction.id)
            var totalPoints = factionEntries.reduce((acc, curr) => acc + curr.points, 0);

            return { ...faction, totalPoints }; // Copies faction properties instead of modifying
        })

        const extendedPlayer = { ...player, factionTotals };

        extendedPlayer.factionTotals.forEach(element => console.log(element.totalPoints))

        return extendedPlayer;
    }))

    playerResults.forEach(player => player.factionTotals.forEach(element => console.log(element.totalPoints)));

    res.send(playerResults);
})

使用spread( ... )复制属性,因此每个玩家迭代的原始factions列表都相同。 创建extendedPlayer的第二步可能不是严格防止您遇到的问题,但也可以使外部map保持纯净。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM