Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 26.04.2015, 03:47
Аспирант
Отправить личное сообщение для FoxTrix Посмотреть профиль Найти все сообщения от FoxTrix
 
Регистрация: 27.07.2012
Сообщений: 73

Массив promise'в (vow)
Доброго времени суток.
Начал писать парсер html, столкнулся с проблемой ожидания promise'ов.
Использую vow.

Есть некий код:
var promises = [], arr = [];

var parseUrl = function (i, url) {
	promises[i] = vow.defer();
	request({uri:url,method:'GET',encoding:'binary'},
		function (err, res, body) {
			var $=cheerio.load(
				iconv.encode(
					iconv.decode(
						new Buffer(body,'binary'),
					'win1251'),
				'utf8')
			);
			arr[i] = $(some_selector).text();
			console.log(arr[i]);
			return promises[i].resolve();
		});
}

var someFunc = (function () {
	var urls = {0:'some_url'};
	
	for(i in urls) {
		parseUrl(i, urls[i]);
	}
	
	vow.all(promises).spread(function () {
		for(i in urls) {
			console.log(arr[i]);
		}
	});
})();


Собственно проблема в том, vow.all не ждёт ответа, а выводит "undefined", а потом выводится console.log с нужной информацией из функции parseUrl.

Если promises объявить как переменную, то проблема решается, но ссылок будет неопределенное кол-во, и соответственно такой вариант мне не подходит.

В документации описано только:
var defer1 = vow.defer(),
	defer2 = vow.defer();

vow.all([defer1.promise(), defer2.promise(), 3])
	.then(function(value) {
		// value is "[1, 2, 3]" here
	});

defer1.resolve(1);
defer2.resolve(2);

что мне не подходит из-за неопределенного кол-ва promise'ов.

Есть ли решение данной проблемы, или стоит присмотреться к другим promise модулям (Q/When)?

ps: io.js поставил 4 часа назад, заранее извиняюсь за возможно очевидные косяки =)

Последний раз редактировалось FoxTrix, 26.04.2015 в 03:50.
Ответить с цитированием
  #2 (permalink)  
Старый 26.04.2015, 07:41
Аватар для Erolast
Профессор
Отправить личное сообщение для Erolast Посмотреть профиль Найти все сообщения от Erolast
 
Регистрация: 24.09.2013
Сообщений: 1,436

Цитата:
Начал писать парсер html
...зачем?
https://www.npmjs.com/package/htmlparser2

Цитата:
Использую vow.
Чем не устраивают родные промайзы, раз уж используешь io.js?
https://developer.mozilla.org/en-US/...bjects/Promise
http://www.2ality.com/2014/10/es6-promises-api.html

Цитата:
promises[i] = vow.defer();
Ты определись, у тебя массив, или карта? Массив - это упорядоченный набор элементов, в него добавляют только с помощью push/unshift. Для хранения пар "произвольный ключ - произвольное значение" в ES6 есть специальный тип Map, и он поддерживается как последней нодой, так и io.js
let promises = new Map();
promises.set(1, new Promise());

https://developer.mozilla.org/en-US/...al_Objects/Map

Цитата:
Собственно проблема в том, vow.all не ждёт ответа, а выводит "undefined"
Не понял. Если бы vow.all возвращал undefined, то у тебя бы на 27-ой строке была ошибка TypeError: vow.all(...) is undefined
Ответить с цитированием
  #3 (permalink)  
Старый 26.04.2015, 07:44
Аватар для Erolast
Профессор
Отправить личное сообщение для Erolast Посмотреть профиль Найти все сообщения от Erolast
 
Регистрация: 24.09.2013
Сообщений: 1,436

Цитата:
var urls = {0:'some_url'};
Опять же - у объекта могут быть только строковые ключи, для числовых ключей используются либо карты, либо массивы.
let urls = new Map([
  [0, "some_url"]
]);

lets urls = ["some_url"];


Цитата:
for(i in urls) {
parseUrl(i, urls[i]);
}
Если уж используешь io.js, почему не кошерный for of? Да, и что это за объявление i без var/let? Ты что, без use strict пишешь? В курсе, что эта переменная попадет в глобал?
for (let [i, url] of urls) {
    parseUrl(i, url);
}

Последний раз редактировалось Erolast, 26.04.2015 в 08:52.
Ответить с цитированием
  #4 (permalink)  
Старый 26.04.2015, 08:09
Аватар для Erolast
Профессор
Отправить личное сообщение для Erolast Посмотреть профиль Найти все сообщения от Erolast
 
Регистрация: 24.09.2013
Сообщений: 1,436

А вообще, как-то так делается:

function parseUrl(url) {
    return new Promise((resolve, reject) => {
        request.get(url, (err, res, body) => {
            if (err) {
                reject(err);
                return;
            }
            
            resolve(body);
        })
    });
}

let urls = ["http://javascript.ru", "http://habrahabr.ru"];

Promise.all(
    urls.map((url) => parseUrl(url))
).then((body) => {
    console.log(`Response arrived: ${body}`);
}).catch((err) => {
    console.log(`Error occured: ${err}`);
});

Последний раз редактировалось Erolast, 26.04.2015 в 08:17.
Ответить с цитированием
  #5 (permalink)  
Старый 26.04.2015, 12:07
Аспирант
Отправить личное сообщение для FoxTrix Посмотреть профиль Найти все сообщения от FoxTrix
 
Регистрация: 27.07.2012
Сообщений: 73

Сообщение от Erolast
...зачем?
https://www.npmjs.com/package/htmlparser2
я знаю что есть модули которые парсят html, собственно по коду видно что использую cheerio.
Видимо неправильно выразился, я пишу не сам парсер, а некую утилиту, которая парсит(с помощью готового модуля), и потом обрабатывает результат.

Сообщение от Erolast
Чем не устраивают родные промайзы, раз уж используешь io.js?
https://developer.mozilla.org/en-US/...bjects/Promise
http://www.2ality.com/2014/10/es6-promises-api.html
тем что я понятия не имел что в io.js есть родные промайзы, т.к. в последней строке написал, что начал его изучать пару часов назад =)

Сообщение от Erolast
Не понял. Если бы vow.all возвращал undefined, то у тебя бы на 27-ой строке была ошибка TypeError: vow.all(...) is undefined
не сама функция, а console.log() который находится в ней.

Сообщение от Erolast
Опять же - у объекта могут быть только строковые ключи, для числовых ключей используются либо карты, либо массивы.
но как-то оно работает

Сообщение от Erolast
Если уж используешь io.js, почему не кошерный for of? Да, и что это за объявление i без var/let? Ты что, без use strict пишешь? В курсе, что эта переменная попадет в глобал?
опять же, т.к. не в курсе про for of.
Про глобал в курсе, тут большая часть кода, это компиляция из нескольких примеров под node.js, переписанная под новый синтаксис vow.
Поэтому пока не разобрался, решил синтаксис не трогать, обратившись к принципу "работает - не трогай".


Попробовал последний пример, вываливается с Unexpected token для '=>'
Может какой-нибудь модуль подключить нужно?
Ответить с цитированием
  #6 (permalink)  
Старый 26.04.2015, 19:49
Аватар для Erolast
Профессор
Отправить личное сообщение для Erolast Посмотреть профиль Найти все сообщения от Erolast
 
Регистрация: 24.09.2013
Сообщений: 1,436

Цитата:
я понятия не имел что в io.js есть родные промайзы
Только это не в io, а во все js.
Цитата:
но как-то оно работает
Приведением ключей к строке - да, будет работать, но лучше использовать вещи по своему назначению.

Цитата:
вываливается с Unexpected token для '=>'
А, да, я ж забыл, стрелочные функции в io.js еще не включены по умолчанию.
Либо запускай ио с флагом --harmony_arrow_functions, либо пропускай код через babel, либо перепеши на обычные функции.

Последний раз редактировалось Erolast, 27.04.2015 в 08:58.
Ответить с цитированием
  #7 (permalink)  
Старый 26.04.2015, 23:33
Аспирант
Отправить личное сообщение для FoxTrix Посмотреть профиль Найти все сообщения от FoxTrix
 
Регистрация: 27.07.2012
Сообщений: 73

переписал на обычные функции, работает, получилось нечто такое:
function parseUrl(url) {
	return new Promise(function(resolve, reject) {
		request.get(url, function(err, res, body) {
			if (err) {
				reject(err);
				return;
			}
			
			var $=cheerio.load(
				iconv.encode(
					iconv.decode(
						new Buffer(body,'binary'),
					'win1251'),
				'utf8')
			);

			var obj = {
				h1 : $(some_selector).text(),
				last : $(some_selector).text()
			}

			resolve(obj);
		})
	});
}

var urls = ["some_url", "some_url", "some_url"];

Promise.all(
	urls.map(parseUrl)
).then(function(obj) {
	console.log(obj);
}).catch(function(err) {
	console.log('Error occured: '+err);
});


Правильно ли я понимаю что возвращаются promise в том же порядке что вызываются, и не получится что вернулся сначала второй, потом первый, т.к. по второй ссылке сервер ответил быстрее?

Последний раз редактировалось FoxTrix, 27.04.2015 в 01:54.
Ответить с цитированием
  #8 (permalink)  
Старый 27.04.2015, 09:02
Аватар для Erolast
Профессор
Отправить личное сообщение для Erolast Посмотреть профиль Найти все сообщения от Erolast
 
Регистрация: 24.09.2013
Сообщений: 1,436

Цитата:
Правильно ли я понимаю что возвращаются promise в том же порядке что вызываются, и не получится что вернулся сначала второй, потом первый, т.к. по второй ссылке сервер ответил быстрее?
Конечно. Заресолвится тот, где сервер ответил быстрее, а возвратятся так, как запросил.
Ответить с цитированием
  #9 (permalink)  
Старый 27.04.2015, 09:05
Аватар для Erolast
Профессор
Отправить личное сообщение для Erolast Посмотреть профиль Найти все сообщения от Erolast
 
Регистрация: 24.09.2013
Сообщений: 1,436

Цитата:
urls.map(parseUrl)
Не надо так делать. Если вдруг захочется добавить в функцию parseUrl дополнительные аргументы, весь код навернется.
urls.map(function(url){return parseUrl(url)})
Ответить с цитированием
  #10 (permalink)  
Старый 27.04.2015, 12:52
Аспирант
Отправить личное сообщение для FoxTrix Посмотреть профиль Найти все сообщения от FoxTrix
 
Регистрация: 27.07.2012
Сообщений: 73

Сообщение от Erolast
Конечно. Заресолвится тот, где сервер ответил быстрее, а возвратятся так, как запросил.
Спасибо! =)

urls.map(function(url){return parseUrl(url)})

да, я сначала так и переписал, когда пытался ещё i в функцию передать, но потом когда понял что возвращаются объекты по очереди, и второй аргумент не нужен немного сократил =)
если что, пример увидел здесь

Большое спасибо, теперь всё работает как нужно! =)

ps может ещё подскажите в сторону какого модуля можно погуглить, чтобы сделать очередь из запросов (чтобы сервер с 503 ошибкой не выкидывал)?
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как в шаблоне диррективы узнать массив это или строка? delias Angular.js 1 18.03.2014 07:33
Отправить, когда четко соберется массив vas88811 Events/DOM/Window 11 26.02.2014 21:55
Массив объектов doox911 Библиотеки/Тулкиты/Фреймворки 6 16.01.2014 22:36
Как создать многомерный массив FRIE Общие вопросы Javascript 29 02.06.2010 19:14
Подскажите, как вернуть js-скрипт массив Polkan AJAX и COMET 18 30.04.2010 23:30