简体   繁体   English

如何在Node.js中正确处理异步函数

[英]How properly handle async functions in nodejs

I am new to nodejs, and I don't properly understand how async functions works. 我是nodejs的新手,我不太了解异步函数的工作原理。 I read about them a lot today, but I cant solve my problem. 今天,我对它们的了解很多,但我无法解决问题。

I use Sequelize.js as the ORM and my problem is when I nest a query into the callback of an other query then I cant force it to continues only when both query ended. 我将Sequelize.js用作ORM,而我的问题是,当我将一个查询嵌套到另一个查询的回调中时,我不能强迫它仅在两个查询都结束时才继续。

Here is my current code: 这是我当前的代码:

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 
    }));
  });
});

When this code is called, the array will be emited in every loop with one more element in it in every loop, but this is not good for me. 当调用此代码时,将在每个循环中发出数组,并在每个循环中再添加一个元素,但这对我不利。 I want to call the emit event once when the array is totally filled. 当数组完全填充时,我想调用一次emit事件。

The preferred way of solving this kind of thing is to use Promise.all 解决这类问题的首选方法是使用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); 
        });
    });
  });
});

edit: 编辑:

If I understand you correctly you want to write return { id: result[i].matchId, name: teams[0].clubName + ' - ' + teams[1].clubName}; 如果我对您的理解正确,那么您要编写return { id: result[i].matchId, name: teams[0].clubName + ' - ' + teams[1].clubName};

But that doesn't work. 但这是行不通的。 That line of code is executed at some point in the future, ie after the for loop has finished and by that time i is -1. 该代码行在将来的某个时间执行,即在for循环完成之后,此时i为-1。 To make it work you need a new variable for each iteration of the loop. 为了使其正常工作,您需要为循环的每次迭代添加一个新变量。 You could do that eg by wrapping the code in another function like this 您可以这样做,例如通过将代码包装在这样的另一个函数中

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);
}

That way you use a different i variable (stored at a different place in memory) in each iteration. 这样,您可以在每次迭代中使用不同的i变量(存储在内存中的不同位置)。 But the best way to do it in this case is to use forEach. 但是在这种情况下,最好的方法是使用forEach。 The only difference is that the loop will iterate through the array forward and not backward as was the case with your for loop. 唯一的区别是循环将向前遍历数组,而不是像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};
    }));
});

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

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