Как заставить http.get (NodeJS) работать синхронно?

Суть проблемы: в цикле я перебираю массив тайлов, и если встречается определённый тип "mark" (показатель), делаю запрос на получение данных извне.

Проблема в том, что цикл успевает пробежать до конца (и даже больше), и в результате tiles[i] становится совсем не тем элементом, который нужен. Как заставить цикл дожидаться выполнения запроса на показатель?
function prepareTiles(tiles, u, s) {
	for (var i = 0, l = tiles.length; i < l; i++) {
		var tmp = tiles[i].metadata;
		switch (tmp.tiletype) {
			case 'mark':
				var options = {
					port: '8080',
					path: '/getSingleMark?'+
						qs.stringify({
							url:    u,
							ssid:   s,
							mark:   tmp.mark,
							type:   tmp.type,
							format: tmp.format,
							graph:  tmp.graph
						}),
					method: 'GET'
				};
				http.get(options, function(res){
					var data = '';
					res.on('data', function(chunk){
						data += chunk.toString();
					}).on('end',function(){
						tiles[i].metadata.value = data;
					}).on('error', function(err){
						console.dir(err);
					});
				});
				break;
			case 'youtube':
				tiles[i].metadata.value = tpl.make(tmp.tiletype, {
					videoid: tmp.videoid
				});
				break;
			case 'telcall':
				tiles[i].metadata.value = tpl.make(tmp.tiletype, {
					name: tmp.name,
					tel: tmp.tel
				});
				break;
			case 'skypecall':
				tiles[i].metadata.value = tpl.make(tmp.tiletype, {
					name: tmp.name,
					tel: tmp.tel
				});
				break;
		}
	}
	return tiles;
}
  • Вопрос задан
  • 3483 просмотра
Решения вопроса 1
К тому же `http` в ноде асинхронное, поэтому нужен `callback` или `promise`. А ещё нужно код отрефакторить. Вот навскидку:
var Request = require('request'),
    Class = require('atma-class');
module.exports = function prepareTiles(tiles, url, ssid, callback) {

    var await = new Class.Await();
    tiles.forEach(function(tile) {
        prepareTile(tile, url, ssid, await.delegate());
    });
    await.always(function(){
        callback(tiles);
    });
};

function prepairTile(tile, url, ssid, callback) {
    var meta = title.metadata;
    switch (meta.tiletype) {
        case 'mark':
            var search = qs.stringify({
                url: url,
                ssid: ssid,
                mark: meta.mark,
                type: meta.type,
                format: meta.format,
                graph: meta.graph
            });
            val_resolve(
                'http://127.0.0.1:8080/getSingleMark?' + search
                , tile
                , callback);
            break;
        case 'youtube':
        case 'telcall':
        case 'skypecall':
            val_onComplete(tile, meta, callback);
            break;
    }
}

function val_resolve(url, tile, callback) {
    Request.get(url, function(error, res, body) {
        if (error)
            console.error(error)
        val_onComplete(tile, body, callback);
    });
}

function val_onComplete(tile, model, callback) {
    tile.metadata.value = tpl.make(
        tile.metadata.tiletype, model
    );
    callback();
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Никак.

Для решения вашей проблемы нужно использовать замыкание. Я не знаток ноды, но например так:
(
	function(tileInfo){
		http.get(options, function(res){
			var data = '';
			res.on('data', function(chunk){
				data += chunk.toString();
			}).on('end',function(){
				tileInfo.metadata.value = data;
			}).on('error', function(err){
				console.dir(err);
			});
		});
	}
)(tiles[i]);

Функцию можете отдельно вынести, если хотите.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы