如何正确处理nodejs中的asynchronous函数

我是nodejs的新手,我不能正确理解asynchronous函数是如何工作的。 我今天读了很多,但是我不能解决我的问题。

我使用Sequelize.js作为ORM和我的问题是当我embedded一个查询到其他查询的callback,然后我不能强迫它只有当两个查询结束时继续。

这是我现在的代码:

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。 为了使它工作,你需要一个新的variables为循环的每个迭代。 你可以做到这一点,例如通过在另一个函数中包装代码

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

这样你在每次迭代中使用一个不同的ivariables(存储在内存中的不同位置)。 但在这种情况下最好的方法是使用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}; })); });