我如何在NodeJS中模拟“睡眠”?

我正在用玩家周围的迷你地图来构build浏览器游戏。 我需要跟踪其他玩家的位置,并在有人移动时更新这个迷你地图。 我在NodeJS和CouchDB中实现了这个function。 我的devise如下:

我有一个数据库所有改变的游戏数据。 在这个数据库中,我有一个包含二维数组中基本地图数据的文档,网格上的每个正方形都由此数组中的一个元素表示。 因为我可以有大量不同的用户同时在地图上移动,所以我需要一些方法来确保我没有阅读别人正在写的信息(如果有大量的用户在阅读,我可能会得到错误的信息)写入单个文档)。 我决定在这个数据库中有单独的文件,代表各个方块,每个文件都有“在”这个方块上的玩家以及与这个方块相关的其他一些数据。 本质上,地图文档仅用作方形文档的查找表。 这使我可以更改单个文档而不必重写整个地图文档,解决了同时读写的问题。

我的问题是,我需要获得一个迷你地图供用户作为参考。 这迷你地图将有周围广场的文件。 由于我同时需要所有这些,所以我认为我只需从数据库中抓取所有9个方格,并将其返回到一个单独的ajax响应中。 我的问题,虽然是减less我阻止IO的数量。 现在,我有一个嵌套循环,请求从数据库中我需要的方格。 这里看看我的代码(位置和地图传入):

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

我的问题是,虽然getDoc是非阻塞的,所以我不知道什么时候将方形数据设置为miniMap。 我想过做这样的事情:

 while(numDone < 9){ sleep(10); } callback(miniMap); 

这将让我等到CouchDB完成获取我的所有数据,但JavaScript没有睡眠function。 我发现最接近的是setTimeout,但这也是非阻塞的,我绝不会100%确定我select超时的时间足以让CouchDB完成获取我的数据。

所以基本上我想有一个条件,testing它,然后返回到事件堆栈,如果条件是错误的。 我想到的唯一的解决scheme是有一个recursionsetTimeoutcallback,可以这样做:

 function testCallback(data, condition, callback){ if(data < condition){ setTimeout(function(){ testCallback(data, condition, callback); }, 10); }else{ callback(data); } } 

这似乎很可怕…有没有更好的办法,我可以做到这一点? 我应该放弃这种方法,并迫使有多个Ajax调用来获取更新的数据? 我应该去阻止方法吗?

只需使用另一个callback:

 function getMiniMap(....., callback) { // supply the callback that sends the data var miniMap = new Array(); var keyMap = new Object(); var numDone = 0; ... numDone++; if (numDone === 9) { // as soon as everything has been collected... callback(miniMap); // ... call the send callback and supply it the miniMap } }); } } } 

哦,你的数据库模型真的很糟糕,我不太了解你的游戏,但是除非这需要在多个Node进程上运行,否则最好把Map等放在一个JS Array中,只写入DB当服务器需要保存状态时。

哦,你也可以用一个匿名函数来replace你的keyMap

  (function(x, y) { gameDB.getDoc(map[i][v].id, function(er, doc){ var tPos = keyMap[doc._id]; miniMap[tPos.y][tPos.x] = doc; numDone++; }); })(x, y); // pass in a copy of x and y 

鉴于我们正在讨论事件编辑系统,我认为它会更干净,如果你可以发出一个加载完成的事件,当numDone == 9,并从你的主要捕捉它,并从那里继续。

即使游戏需要在多个节点上运行,也可以将整个地图放在redis中。