嵌套Array.map()的ES6 Promises

时间:2017-06-29 12:29:23

标签: javascript node.js

我正在开展一个项目,我希望其中一个功能可以返回修改后的“播放器”。对象

想象一下,如果你有一个等于的玩家(下面不是真正的代码,但逻辑是相同的):

{
    id: 1,
    val: 590
}

和stats(对象数组)等于:

[
    {
        id: 1,
        val: 400
    }
    {
        id: 2,
        val: 590
    }
]

问题在于,当我进行嵌套映射(.map())时,我的播放器以某种方式返回(解析)比map函数结束迭代更快。但是,我希望它只在所有迭代完成后返回

我尝试了什么:我找到了实现计数的解决方案,并检查它是否等于outter map函数。它既不起作用,因为我的代码发送得太快(在迭代完成之前),或根本没有解决。

我非常感谢听到任何建议,甚至是实践(我应该这样做还是不行),因为我试图解决这个问题将近2天。

这是近似的样子(原始的更复杂):

以下是代码的链接:https://jsfiddle.net/j0ownf0m/

const do_magic_with_measurements = (db, data) => {
  let session = data.session;
  let player = data.player;
  let count = 0;

  return new Promise((resolve, reject) => {
      session.Measurements.map(measurement => {
        player.Stats.map(stat => {
          if (measurement.Type === stat.Type) {
            /* Update maximum value */
            if (measurement.MaxValue === stat.MaxValue) {
              db.collection(SESSIONS_COLLECTION)
                .find({
                  PlayerID: ObjectID(session.PlayerID),
                  "Measurements.Type": measurement.Type
                }, {
                  "Measurements.$": 1
                })
                .sort({
                  "Measurements.MaxValue": -1
                })
                .toArray()
                .then(one_session => {
                  console.log(one_session);
                  if (one_session[0].Measurements[0].MaxValue == stat.MaxValue) {
                    // update maximum value if they were equal
                    stat.MaxValue = 0;
                  } else {
                    // otherwise set the next maximum value
                    stat.MaxValue = one_session[0].Measurements[0].MaxValue;
                  }
                })
                .catch(error => {
                    throw error;
                    .catch(error => {
                      throw error;
                    });
                  }
                }

            });
        });
        count++;
        if (count === session.Measurements.length) {
          resolve(player);
        }
      });
    };

1 个答案:

答案 0 :(得分:0)

如果您可以使用async / await模式,那么您可以通过以下方式更改问题中的代码。这将允许您迭代玩家,一旦您的功能完成,您可以使用更改的玩家数据做一些事情

注意,因为它们是引用,所以它们会在原始数组中进行更改,如果您不想要它,您可以深度克隆数组,并在那里进行更改

请注意,此处提出的代码基于your jsfiddle,并显示了如何使用async / await模式更改它的抽象方式



const mockedData = [
  { player: 1, value: 1000 },
  { player: 2, value: 1500 },
  { player: 3, value: 1900 }
];

const mockedPlayers = [
  { player: 1, value: 1000 },
  { player: 2, value: 1500 },
  { player: 3, value: 1900 }
];

async function findArrayInDb(matchBy, sortBy) {
  // here you could create your db call 
  // and use the arguments for the property filtering
  // for now, always the same comes out
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve( mockedData ), 1000);
  });
}

const doDelayedPromisesWork = async (players) => {
  for (let i = 0; i < players.length; i++) {
    let player = players[i];
    let result;
    result = await findArrayInDb( player );
    if (player.player === result[0].player) {
      console.log('found player');
      player.value = 0;
    } else {
      console.log('player was not the first');
      player.value += 500;
    }
  }
  // no need to return, the players are reference types so they will be changed inside the for loop
};

const doPlayerMagic = async () => {
  console.log('iterating mocked players');
  var result = await doDelayedPromisesWork( mockedPlayers );
  return new Promise(resolve => resolve());
};

doPlayerMagic().then(() => /*completed iteration of the players*/ console.log('finished'));
// runs before anything happens with the players
console.log('instructions send');
&#13;
&#13;
&#13;