Метеор (Волокна) петля и обратный вызов

Режим "синхронизации" метеорных волокон сводит меня с ума. Вот простой пример кода:

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.

Другие вопросы по тегам