如何正确处理 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};
}));
});
我是 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};
}));
});