我在mongodb中有一个Collection,其中包含嵌入的引用文档,这迫使我运行多个anon函数。
首先我初始化这个数组
var player = {
name : '',
life : 10,
gold : 50,
score : 0,
clientId : socket.id,
playerId : data.playerId,
deck : []
};
现在我需要通过从mongodb获取数据来向数据库添加数据。
// First find the player.
var playerCol = db.collection('Guest');
playerCol.find({'_id' : new ObjectId(data.playerId)}).toArray(function(err, playerRes) {
// Traverse and load each tower in deck.
// Traverse each embedded reference, so each can be fetched.
playerRes[0].deck.towers.forEach(function(tower) {
// fetch data for tower.
towerCol = db.collection('Tower');
towerCol.find({'_id' : new ObjectId(tower.oid)}).toArray(function(err, completeTower) {
// Add the tower data to the deck.
player.deck.push(completeTower.pop());
});
});
现在问题是播放器阵列在第一次初始化时仍然保持原样。为什么播放器中的数据不存在?我知道为什么,因为它在另一个范围内,而不是在匿名函数内部调用。但是我应该如何将我的值添加到播放器数组呢?
整个片段。
// Initialize the player.
var player = {
name : '',
life : 10,
gold : 50,
score : 0,
clientId : socket.id,
playerId : data.playerId,
deck : []
};
// Load players deck.
var playerCol = db.collection('Guest');
playerCol.find({'_id' : new ObjectId(data.playerId)}).toArray(function(err, playerRes) {
// Traverse and load each tower in deck.
playerRes[0].deck.towers.forEach(function(tower) {
towerCol = db.collection('Tower');
towerCol.find({'_id' : new ObjectId(tower.oid)}).toArray(function(err, completeTower) {
player.name = "Melvar";
player.deck.push(completeTower.pop());
console.log(player.deck); // Prints the data, just pushed
});
});
console.log(player.deck); // Prints empty array.
process.exit(1);
答案 0 :(得分:0)
虽然Node.JS是单线程的,但它基于事件。做好工作,等待其他工作完成。等待MongoDB调用返回是一个可以“等待”的完美示例。在这种情况下,这意味着当Node进程正在等待响应时,它可以执行其他JavaScript代码。最终,MongoDB响应,代码在下一次“等待其他工作”机会时执行。
下面标记为#1,代码在playerCol.find
返回之前执行。 Node.JS和MongoDB驱动程序是异步的。这意味着在初始调用之后,才会返回调用find
的结果。稍后,当数据库响应值时,将进行回调。在第一次调用playerCol.find
时,回调是在toArray中声明的内部函数。我已将其重命名为findPlayerAsync.
因此,在执行find之后,下一行运行的是console.log(player.deck)
。如果您添加标记字符串after find:
,您将看到该值在另一个console.log
执行之前显示在控制台上(标记为#2)。
// Load players deck.
var playerCol = db.collection('Guest');
playerCol.find({'_id' : new ObjectId(data.playerId)}).toArray(function findPlayerAsync(err, playerRes) {
// Traverse and load each tower in deck.
playerRes[0].deck.towers.forEach(function(tower) {
towerCol = db.collection('Tower');
towerCol.find({'_id' : new ObjectId(tower.oid)}).toArray(function findTowerAsync(err, completeTower) {
player.name = "Melvar";
player.deck.push(completeTower.pop());
console.log('Inside towerCol.find: ' + player.deck); // #2 Prints the data, just pushed
});
});
console.log('After find: ' + player.deck); // #1 Prints empty array.
process.exit(1);
我希望控制台是:
After find: []
Inside towerCol.find: [......]