Couchdb 我该如何效仿;“睡眠”;在NodeJS?

Couchdb 我该如何效仿;“睡眠”;在NodeJS?,couchdb,node.js,Couchdb,Node.js,我正在构建一个浏览器游戏,其中包含玩家周围环境的迷你地图。我需要跟踪其他玩家的位置,并在有人移动时更新这个迷你地图。我正在NodeJS和CouchDB中实现这一点。我的设计如下: 我有一个数据库,用于所有不断变化的游戏数据。在这个数据库中,我有一个文档,其中包含二维数组中的基本地图数据,网格上的每个正方形由该数组中的一个元素表示。因为我可能会有大量不同的用户同时在地图上移动,所以我需要某种方法来确保我不会在别人向地图上写东西时被读取(如果大量用户对单个文档读写,我可能会得到错误的信息)。我决定在

我正在构建一个浏览器游戏,其中包含玩家周围环境的迷你地图。我需要跟踪其他玩家的位置,并在有人移动时更新这个迷你地图。我正在NodeJS和CouchDB中实现这一点。我的设计如下:

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

不过,我的问题是,我需要一张迷你地图供用户参考。这张迷你地图将包含周围广场的文件。由于我同时需要所有这些,我想我应该从数据库中获取所有9个方块,并在一个ajax响应中返回它。不过,我的问题是如何减少阻塞IO的数量。现在,我有一个嵌套循环,它从数据库中请求我需要的方块。下面是我的代码(位置和地图已传入):

var miniMap=newarray();
var keyMap=新对象();
var numDone=0;
对于(i=position.y-1,y=0;i
不过,我的问题是getDoc是非阻塞的,所以我不知道它何时会将正方形数据设置为miniMap。我想做这样的事情:

while(numDone < 9){
    sleep(10);
}
callback(miniMap);
function testCallback(data, condition, callback){
    if(data < condition){
        setTimeout(function(){
            testCallback(data, condition, callback);
        }, 10);
    }else{
        callback(data);
    }
}
while(numDone<9){
睡眠(10);
}
回叫(小地图);
这将让我等待CouchDB完成获取所有数据,但JavaScript没有睡眠功能。我找到的最接近的是setTimeout,但这也是非阻塞的,我永远不会100%确定我为超时选择的时间是否足以让CouchDB完成获取我的数据

所以基本上我想要有一个条件,测试它,如果条件为false,那么再次将它返回到事件堆栈。我想到的唯一解决方案是使用递归setTimeout回调,它可以执行以下操作:

while(numDone < 9){
    sleep(10);
}
callback(miniMap);
function testCallback(data, condition, callback){
    if(data < condition){
        setTimeout(function(){
            testCallback(data, condition, callback);
        }, 10);
    }else{
        callback(data);
    }
}
函数testCallback(数据、条件、回调){
如果(数据<条件){
setTimeout(函数(){
testCallback(数据、条件、回调);
}, 10);
}否则{
回调(数据);
}
}

这看起来很可怕。。。有没有更好的办法让我这么做?我是否应该放弃这种方法,强制进行多个ajax调用以获取更新的数据?我应该使用阻塞方法吗?

只需使用另一个回调:

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
                }
            });
        }
    }
}
哦,你的数据库模型真的很糟糕,我对你的游戏不太了解,但除非这需要在多个节点进程上运行,否则最好将地图等保存在JS数组中,并且只在服务器需要保存状态时写入数据库

哦,您还可以用匿名函数调用替换
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时发出一个load done事件,并从您的main捕获它,然后从那里继续,那么会更干净


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

我想我在地图部分做得都不对。将所有内容保存在内存中而不是数据库中肯定是一种更简单的方法。我想我会继续,把所有的东西都放在我的地图文档中,只在需要重新启动或其他什么的时候保存状态。谢谢你的帮助!!也请查收。启动redis服务器,然后在节点中使用redis模块。您先给出一个字符串键,然后是一个json对象,然后BAM保存的所有子项和数据。将其加载并使用该键将其再次作为对象返回到内存中。还可以考虑作为ReDIS或关系数据存储的一种替代方法,以用于这种类型的状态信息。Firebase将实时将状态同步到所有连接的客户端。它是为您的应用类型而设计的。