我正在开发一个小型Web应用程序,以跟踪本地棋盘游戏小组的积分。计分板将跟踪玩家玩过的游戏总数,获得的总积分,玩过的游戏的细目分类以及游戏中每个派系可获得的得分。
我目前正在撞墙,试图为/ players / withFactions /创建节点/表达端点,这将返回聚合的玩家数据以及每个派系的故障。
正如您在所附的代码中看到的那样,逻辑正确运行,并且数据在第一个console.log的位置正确。该数据只是返回了,我将返回值记录在第二个控制台日志中,那里的数据似乎已更改。突变的数据似乎总是采用第一个console.log位置中最后返回的元素的形式。我希望这在审查代码时会更有意义。
我确定我的问题在于我如何处理所有异步操作,但是我无法找出解决方案。
我已经以多种不同方式攻击了此问题:回调,promise,异步/等待。所有结果都相同。在返回前端之前,数据似乎在改变我。
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.factionTotal,其余的玩家数据仍保持准确。
我确信那里等待的次数比必要的多。我一直在研究这个问题太久了。希望我能对此有所帮助。
答案 0 :(得分:1)
Jaromanda X所标识的问题是,您为每个玩家修改了factions
,因此只有最后一次修改会“停留”。
通常,我建议使用地图时不要有副作用,而只返回新对象或未修改的对象。为此,您应该可以将代码修改为如下形式:
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);
})
使用跨度(...
)复制属性,因此原始factions
列表对于每个玩家迭代都是相同的。创建extendedPlayer
的第二步可能不是严格防止您遇到的问题,但也可以使外部map
保持纯净。