queue.js: difference between array of functions &

2019-08-07 08:57发布

So, I am trying to make sure that a series of HTTP GET requests happen before I try to render the data gotten into a visualization. Typical deal, right?

I'm using queue.js, and seeing this on the queue.js github page (https://github.com/mbostock/queue):

Or, if you wanted to run a bazillion asynchronous tasks (here represented as an array of closures) serially:

    var q = queue(1);
    tasks.forEach(function(t) { q.defer(t); });
    q.awaitAll(function(error, results) { console.log("all done!"); });

Queue.js can be run inside Node.js or in a browser.

So, what I did was made an array of functions, each of which contained a Meteor.http.get call (as I'm using Meteor.js) and then followed this line by line.

It seems like what is happening is that while my array -- which has 8 functions in it, all with what looks like the right function in each slot -- gets populated (and then passed as in the code exceprt to defer,) only one actually runs.

Here's what I'm wondering. Well, overall it's, why is only one function running though 8 are passed in to defer? But specifically it's -- having a hazy understanding of closures, I really have an array of functions. Is there something I missed there, since the documentation specifically says closures, which is why all the functions aren't executing?

Thank you for looking at this!

1条回答
孤傲高冷的网名
2楼-- · 2019-08-07 09:15

Here is perhaps the literal part of the statement you quoted, found in the test suite:

"queue of asynchronous closures, processed serially": {
    topic: function() {
        var tasks = [], 
            task = asynchronousTask(),
            n = 10,
            q = queue(1);

        while (--n >= 0) tasks.push(task);

        tasks.forEach(function(t) { q.defer(t); });

        q.awaitAll(this.callback)
    },
    "does not fail": function(error, results) {
        assert.isNull(error);
    },
    "executes all tasks in series": function(error, results) {
        assert.deepEqual(results, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
    }
},

https://github.com/mbostock/queue/blob/master/test/queue-test.js#L103

Which runs task = asynchronousTask(), which is what is pulled off the queue and invoked

function asynchronousTask() {
    var active = 0;

    return function(callback) {
        ++active;

        process.nextTick(function() {
            try {
                callback(null, active);
            } finally {
              --active;
            }
        });
    };
}

The above, inner return function() {...} is what I believe is being referenced as a closure which retains it's reference in scope to the outer active variable as each asynchronous function is called off the queue.

This is, of course, fairly powerful in terms of callbacks and handlers, since it gives you the means to maintain and manipulate a locally shared variable, for instance if you want to know how many functions were returned, and when the list has been exhausted. In other words, a queue.

The following is not used in the example up top, but use it as a reference point to see how it differs from the synchronousTask function above.

function synchronousTask() {
    var active = 0;

    return function(callback) {
        try {
            callback(null, ++active);
        } finally {
            --active;
        }
    };
}

https://github.com/mbostock/queue/blob/master/test/queue-test.js#L265

查看更多
登录 后发表回答