Метеор (Волокна) петля и обратный вызов
Режим "синхронизации" метеорных волокон сводит меня с ума. Вот простой пример кода:
var feedsData = feeds.fetch(); // [{_id: "1234"}, {_id: "6789", url: "http://...."}]
for(var i = 0, len = feedsData.length; i < len; i++) {
var feed = feedsData[i];
parser.parseURL(feed.url, function(err, out){
console.log(feed._id, i); // outputs "6789" and "2" each times
});
}
Я не понимаю, как заставить это работать. Обратный вызов вызывается после завершения цикла, но внутренние внутренние переменные, такие как feed, должны быть сохранены... а это не так.
Проанализированные URL-адреса хорошие (первый, затем второй), но затем я не могу обновить свои данные, поскольку у меня нет хорошего _id в обратном вызове.
Требуемый результат будет: "1234", "0" и "6789" "1", а не "6789" "2" оба раза... Как бы вы сделали это в коде Метеор / Волокно?
4 ответа
Другой способ сделать это в "волокне"(и это, вероятно, лучше, чем ответ с "будущим", который я разместил выше):
var feedsData = feeds.fetch(); // [{_id: "1234"}, {_id: "6789", url: "http://...."}]
Fiber(function() {
var fiber = Fiber.current;
for(var i = 0, len = feedsData.length; i < len; i++) {
var feed = feedsData[i];
parser.parseURL(feed.url, function(err, out) {
console.log(feed._id, i);
if(err) return fiber.throwInto(err);
fiber.run();
});
Fiber.yield();
console.log('here', i);
}
console.log('there');
}).run();
console.log('and there');
Выход будет:
"and there"
"1234" "0"
"here" "0"
"6789" "1"
"here" "1"
"there"
Обратите внимание, что все функции Fiber выполняются в своем собственном волокне, как если бы оно было асинхронным, поэтому "а там" выводится первым
Не уверен, что это имеет какое-либо отношение к метеору, волокнам или "режиму синхронизации". Я думаю, что это просто ошибка в вашем JavaScript. Вы перебираете массив, а затем вызываете свойство объекта в обратном вызове. Конечно, когда обратный вызов в конце концов вызывается, он будет смотреть на текущее значение feed
, который будет самым последним назначенным после завершения цикла.
Поэтому вы должны переписать свой код, чтобы учесть это:
var feedsData = [{_id: "1234"}, {_id: "6789", url: "http://...."}]
for(var i = 0, len = feedsData.length; i < len; i++) {
var feed = feedsData[i];
parser.parseURL(feed.url, function(err, out){
console.log(this._id, arguments[0]); // will output "1234 0" and "6789 1"
}.bind(feed, i));
}
Самое простое решение:
feeds.fetch().forEach(function(feed,i) {
parser.parseURL(feed.url, function(err, out){
console.log(feed._id, i);
});
});
Javascript не имеет блока видимости (пока, let
идет в ES6), только функция обзора.
Хорошо, вот "волоконный" способ сделать это:
var Future = require('fibers/future'),
wait = Future.wait,
feedsData = feeds.fetch(); // [{_id: "1234"}, {_id: "6789", url: "http://...."}],
parseUrl = Future.wrap(parser.parseURL);
Fiber(function() {
for(var i = 0, len = feedsData.length; i < len; i++) {
var feed = feedsData[i];
var out = parseUrl(feed.url).wait();
console.log('here', i, out);
}
console.log('there');
}).run();
console.log('and there');
Результат будет:
"and there"
"here" "0" "the out data from the 1st callback"
"here" "1" "the out data from the 2nd callback"
"there"
Как раз то, что вы ожидаете. "Будущее" в Fibers ожидает, что последний параметр, переданный функции, является обратным вызовом, и в качестве первого параметра вернет err.