如何正确处理 nodejs 中的异步函数

How properly handle async functions in nodejs

我是 nodejs 的新手,我不太了解异步函数的工作原理。我今天读了很多关于它们的文章,但我无法解决我的问题。

我使用 Sequelize.js 作为 ORM,我的问题是当我将查询嵌套到另一个查询的回调中时,我无法强制它仅在两个查询结束时继续。

这是我当前的代码:

io.on('connection', function (socket) {
  socket.on('join', function (data) {
    clients[clients.length] = new Client("Client " + clients.length, data.channel);
    console.log('Client connected Channel: ' + clients[clients.length-1].channel);
    var array = []
    DB.Matches.findAll({attributes: ['matchId', 'teamAId', 'teamBId']}).then(function (result) {
      for (var i = result.length - 1; i >= 0; i--) {
        DB.Teams.findAll({where: { team_id: [result[i].teamAId,result[i].teamBId]}}).then(function (teams) {
          array.push({ id: 0, name: teams[0].clubName + ' - ' + teams[1].clubName});         
        }).then(function () {
          // Now my emit event is here but I dont want to run every time the  loop run
          console.log(array);
          socket.emit('matches', array); 
        });
      }
    }.then(function () {
      // I tried to put it here, but then I got an empty array, because the queries haven't finshed yet 
    }));
  });
});

当调用此代码时,数组将在每个循环中发出,每个循环中都包含一个元素,但这对我不利。我想在数组完全填满时调用一次 emit 事件。

解决这种事情的首选方法是使用Promise.all

io.on('connection', function (socket) {
  socket.on('join', function (data) {
    clients[clients.length] = new Client("Client " + clients.length, data.channel);
    console.log('Client connected Channel: ' + clients[clients.length-1].channel);
    DB.Matches.findAll({attributes: ['matchId', 'teamAId', 'teamBId']}).then(function (result) {
      var promises = [];
      for (var i = result.length - 1; i >= 0; i--) {
        promises.push(
          DB.Teams.findAll({where: { team_id: [result[i].teamAId,result[i].teamBId]}}).then(function (teams) {
             return { id: 0, name: teams[0].clubName + ' - ' + teams[1].clubName};         
          }));
      }
      Promise.all(promises).then(function(array) {
          console.log(array);
          socket.emit('matches', array); 
        });
    });
  });
});

编辑:

如果我理解正确的话你想写 return { id: result[i].matchId, name: teams[0].clubName + ' - ' + teams[1].clubName};

但这不起作用。那行代码会在未来的某个时刻执行, 即在 for 循环完成后,到那时我是 -1。 为了使其工作,您需要为循环的每次迭代创建一个新变量。 你可以这样做,例如通过将代码包装在另一个函数中,例如

for(var i = result.length - 1; i >= 0; i--) {
  (function(i) {
    promises.push(
      DB.Teams.findAll({where: { team_id: [result[i].teamAId,result[i].teamBId]}}).then(function (teams) {
         return { id: result[i].matchId, name: teams[0].clubName + ' - ' + teams[1].clubName};
      }));
  })(i);
}

这样您就可以在每次迭代中使用不同的 i 变量(存储在内存中的不同位置)。 但在这种情况下最好的方法是使用 forEach。唯一的区别是循环将 向前遍历数组而不是像 for 循环那样向后遍历数组。

result.forEach(function(match) {
  promises.push(
    DB.Teams.findAll({where: { team_id: [match.teamAId,match.teamBId]}}).then(function (teams) {
       return { id: match.matchId, name: teams[0].clubName + ' - ' + teams[1].clubName};
    }));
});