Skip to content Skip to sidebar Skip to footer

Learnyounode - Jugglling Async (#9) - I Must Be Missing Something

There seem to be many questions about this problem out here, but none directly relate to my question AFAICT. Here is the problem statement: This problem is the same as the previo

Solution 1:

They use a counter to count the number of callbacks while I am comparing the length of two arrays (one whose length increases every callback); does that matter?

Yes, it does matter. The .length of an array depends on the highest index in the array, not the actual number of assigned elements.

The difference surfaces only when the results from the asynchronous requests come back out of order. If you first assign index 0, then 1, then 2 and so on, the .length matches the number of assigned elements and would be the same as their counter. But now try out this:

var results = []
console.log(results.length) // 0 - as expected
results[1] = "lo ";
console.log(results.length) // 2 - sic!
results[0] = "Hel";
console.log(results.length) // 2 - didn't change!
results[3] = "ld!";
console.log(results.length) // 4
results[2] = "Wor";
console.log(results.length) // 4

If you would test the length after each assignment and output the array whenever you get 4, it would print

"Hello ld!""Hello World!"

Solution 2:

So it turns out there were two different issues here, one of which was pointed out by @Bergi above. The two issues are as follows:

  • The .length method does not actually return the number of elements in the array. Rather it returns the highest index that is available. This seems quite silly. Thanks to @Bergi for pointing this out.
  • The scoping of the i variable is improper, and as such the value of i can change. This causes a race condition when results come back.

My final solution ended up being as follows:

var http = require('http')
var concat = require('concat-stream')

var args = process.argv.slice(2, 5)
var args_len = args.lengthvar results = []
var count = 0functionget_url_save(url, idx) {
    http.get(url, function(res) {
        res.setEncoding('utf8')
        res.pipe(concat(function(str) {
            results[idx] = str
            if (++count === args_len)
                results.forEach(function(val) {
                    console.log(val)
                })
        }))
    }).on('error', console.error)
}

args.forEach(function(arg, i) {
    get_url_save(arg, i)
})

Breaking the outtermost forEach into a method call solves the changing i issue since i gets passed in as parameter by value, thus never changing. The addition of the counter solves the issue described by @Bergi since the .length method isn't as intuitive as one would imagine.

Post a Comment for "Learnyounode - Jugglling Async (#9) - I Must Be Missing Something"