I am building a browser game with a mini map of the surroundings of the player. I need to track where other players are and update this mini map whenever someone moves. I am implementing this in NodeJS and CouchDB. My design goes as follows:
I have a database for all changing game data. In this database, I have a document that contains the basic map data in a two-dimensional array, with each square on the grid being represented by an element in this array. Since I could have tons of different users all moving about the map simultaneously, I needed some way to ensure that I don't get a read as someone else is writing to it (I could get faulty information if a ton of users are reading and writing to a single document). I decided to have separate documents in this database which represent the individual squares, and each document has the players that are "on" that square and some other data associated with that square. Essentially, the map document is used only as a lookup table for the square document. This enables me to change a single document without having to rewrite the entire map document, solving the problem of simultaneous reads and writes.
My problem, though, is that I need to get a mini map for the user to use as a reference. This mini map will have the documents of the surrounding squares. Since I need all of this at the same time, I thought I would just grab all 9 squares from the database and return it in a single ajax response. My problem though is with reducing the amount of blocking IO that I do. Right now, I have a nested loop that requests the squares I need from the database. Here's a look at my code (position and map are passed in):
var miniMap = new Array();
var keyMap = new Object();
var numDone = 0;
for(i = position.y - 1, y = 0; i < position.y + 1 && i < map.length; i++, y++){
miniMap[i] = new Array();
for(v = position.x - 1, x = 0; v < position.x + 1 && v < map.length; v++, x++){
keyMap[map[i][v].id] = {'x': x, 'y': y};
gameDB.getDoc(map[i][v].id, function(er, doc){
var tPos = keyMap[doc._id];
miniMap[tPos.y][tPos.x] = doc;
numDone++;
});
}
}
My problem, though, is that getDoc is non-blocking, so I don't know when it will set the square data to miniMap. I thought about doing something like this:
while(numDone < 9){
sleep(10);
}
callback(miniMap);
This will let me wait until CouchDB is finished getting all of my data, but JavaScript doesn't have a sleep function. The closest I found was setTimeout, but that is also non-blocking and I'll never be 100% sure that the time I chose for the timeout will be sufficient to allow CouchDB to finish getting my data.
So basically I want to have a condition, test it, then return it to the event stack again if the condition is false. The only solution I thought of was to have a recursive setTimeout callback that would do something like this:
function testCallback(data, condition, callback){
if(data < condition){
setTimeout(function(){
testCallback(data, condition, callback);
}, 10);
}else{
callback(data);
}
}
This seems pretty terrible... Is there a better way that I could be doing this? Should I give up this approach and force there to be multiple ajax calls to get updated data? Should I go for a blocking approach?