Call an asynchronous function in a callback

I am having trouble understanding asynchronous functions. I read a chapter in Mixu Node Book , but I still can't wrap myself around it.

Basically, I want to query ressource (using the Node cheerio package), cheerio it for valid URLs and add each match to my redis set setname .

The problem is that in the end, it only adds the first match to the redis set.

 function parse(url, setname) { request(url, function (error, response, body) { if (!error && response.statusCode == 200) { $ = cheerio.load(body) // For every 'a' tag in the body $('a').each(function() { // Add blog URL to redis if not already there. var blog = $(this).attr('href') console.log("test [all]: " + blog); // filter valid URLs var regex = /http:\/\/[^www]*.example.com\// var result = blog.match(regex); if(result != null) { console.log("test [filtered]: " + result[0]); redis.sismember(setname, result[0], function(err, reply) { if(!reply) { redis.sadd(setname, result[0]) console.log("Added " + result[0]) } redis.quit() }) } }) } }) } 

I would be very grateful for pointers on how I would have to restructure this, so the redis.sadd method works with the correct result.

The result of the current implementation looks like this:

 test [all]: http://test1.example.com/ test [filtered]: http://test1.example.com/ ... Added http://test2.example.com/ 

So, he adds test1.example.com, but does not print the "added" line, and he does not add test2.example.com, but he prints the "added" line for him.

Thanks!

+4
source share
1 answer

The first problem is caused by the fact that redis.sismember() is asynchronous: when its callback is called, you have already overwritten the result variable so that it points to the last value that it had, and not the value when you called redis.sismember()

One way to solve this problem is to create a new variable with a scope by wrapping the asynchronous function in closure:

 (function(result) { redis.sismember(setname, result[0], function(err, reply) { ... }); })(result); 

Another option is to create a partial function that is used as a callback:

  redis.sismember(setname, result[0], function(result, err, reply) { ... }.bind(this, result)); 

The second problem, in my opinion, is caused by the call to redis.quit() , which closes the Redis connection after the first sadd() . You do not check err , but if you do, it can tell you more.

+2
source

Source: https://habr.com/ru/post/1481557/


All Articles