Подтвердить что ты не робот

Как эмулировать "сон" в NodeJS?

Я создаю браузерную игру с мини-картой окружения игрока. Мне нужно отслеживать, где находятся другие игроки, и обновлять эту мини-карту всякий раз, когда кто-то перемещается. Я реализую это в NodeJS и CouchDB. Мой дизайн выглядит следующим образом:

У меня есть база данных для всех изменяющихся игровых данных. В этой базе данных у меня есть документ, содержащий основные данные карты в двумерном массиве, причем каждый квадрат на сетке представлен элементом в этом массиве. Поскольку у меня могло быть много разных пользователей, все перемещающиеся по карте одновременно, мне нужен был какой-то способ, чтобы я не читал, как кто-то пишет на него (я мог получить информацию о неисправности, если тонна пользователей читает и запись в один документ). Я решил иметь отдельные документы в этой базе данных, которые представляют собой отдельные квадраты, и в каждом документе есть игроки, которые "on", этот квадрат и некоторые другие данные, связанные с этим квадратом. По существу, документ карты используется только как таблица поиска для квадратного документа. Это позволяет мне изменить один документ без необходимости переписывать весь документ карты, решая проблему одновременного чтения и записи.

Моя проблема заключается в том, что мне нужно получить мини-карту для использования пользователем в качестве ссылки. Эта мини-карта будет иметь документы окружающих квадратов. Поскольку мне нужно все это одновременно, я думал, что просто возьму все 9 квадратов из базы данных и верну их в один ответ ajax. Моя проблема заключается в том, что я уменьшаю количество блокирующих 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 не имеет функции сна. Самое близкое, что я нашел, было setTimeout, но это также не блокирует, и я никогда не буду на 100% уверен, что время, которое я выбрал для таймаута, будет достаточным, чтобы позволить CouchDB закончить получение моих данных.

Итак, в основном я хочу иметь условие, протестировать его, а затем снова вернуть его в стек событий, если условие ложно. Единственное решение, о котором я думал, это иметь рекурсивный обратный вызов setTimeout, который бы сделал что-то вроде этого:

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

Это кажется довольно ужасным... Есть ли лучший способ, которым я мог бы это сделать? Должен ли я отказаться от этого подхода и заставить там быть несколькими вызовами ajax для получения обновленных данных? Должен ли я пойти на блокирующий подход?

4b9b3361

Ответ 1

Просто используйте другой обратный вызов:

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, было бы лучше сохранить Карта и т.д. В массиве 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

Ответ 2

Учитывая, что мы говорим о системе с событиями, я думаю, что было бы более чистым, если бы вы могли просто выпустить событие, сделанное при загрузке, когда numDone == 9 и поймать его из вашего основного источника и перейти оттуда.

Вы можете поместить всю карту в redis, даже если игра должна выполняться через несколько узлов.