Meteor (Fibers) loop and callback

落爺英雄遲暮 提交于 2019-12-09 23:50:14

问题


Meteor fibers "sync" mode is driving me crazy. Here is a simple code example :

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
    });
}

I don't understand how to make this work. The callback is called after the loop is over, but the internal internal variables such as feed should be preserved... and they are not.

The url parsed are good (the first one, then the second one), but then i can't update my data since I don't have the good _id in the callback.

The wanted output would be: "1234" "0" and "6789" "1", not "6789" "2" both times... How would you make this in Meteor / Fiber code ?


回答1:


Another way to do it in the "fiber"(and it is probably better than the answer with "future" I posted above) :

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');

The output will be :

"and there"
"1234" "0"
"here" "0"
"6789" "1"
"here" "1"
"there"

Note that everything in the Fiber function is executed in its own fiber as if it was asynchrone, which is why "and there" is outputed first




回答2:


Not sure this has anything to do with Meteor, Fibers or "sync mode". I think it's just a bug in your javascript. You're looping through an array and then invoking a property of an object within a callback. Of course when the callback eventually is called, it will look at the current value of feed, which will be the most recently assigned one after the loop exited.

So you should rewrite your code to take that into account:

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));
}



回答3:


The simplest solution is:

feeds.fetch().forEach(function(feed,i) {
    parser.parseURL(feed.url, function(err, out){
        console.log(feed._id, i);
    });
});

Javascript does not have block scoping (yet, let is coming in ES6), only function scoping.




回答4:


Ok, here is the "fiber" way of doing that :

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');

The result output will be :

"and there"
"here" "0" "the out data from the 1st callback"
"here" "1" "the out data from the 2nd callback"
"there"

Just what you would expect. The "future" in Fibers expects that the last parameter given to the function is a callback, and will return err as the first parameter



来源:https://stackoverflow.com/questions/15632073/meteor-fibers-loop-and-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!