Why is this javascript block located in Node.js?

I have the following simple HTTP server using Node.js:

var http = require('http'); var server = http.createServer(function(req, res) { var counter = 0; for(var i = 1; i <= 30; i++) { http.get({ host: "www.google.com" }, function(r) { counter++; res.write("Response " + counter + ": " + r.statusCode + "\n"); if(counter == 30) res.end(); }); } }); server.listen(8000); 

When I hang on my local host on port 8000, I get the expected result:

 Response 1: 200 Response 2: 200 Response 3: 200 ... Response 30: 200 

But when I try to hang from another terminal during the first process, I see that the console hangs and waits for the first process to complete before it starts to get the same result.

I realized that since this is asynchronous code using callbacks that a node can handle multiple requests in synchronization, processing them at the next tick of the event loop. And actually I even watched a video about Ryan Dahl doing something similar with a welcoming example of the world. What in my code does the server block do?

+6
source share
3 answers

Your problem has nothing to do with call blocking; this is due to the fact that you can open a certain number of connections simultaneously to one host. After you click the maximum number of open connections, other asynchronous calls to http.get will have to wait until the number of open connections decreases again, which will happen when the remaining requests are completed and their callbacks are started. Since you create new queries faster than they flow, you get your seemingly blocking results.

Here is a modified version of your program that I created to test this. (Note that there is an easier way to solve your problem, as mtomis points out - more on this below.) I added some console.log logs, so itโ€™s easier to say what things were being processed; I also reject all requests for anything other than / , so favicon.ico requests are ignored. Finally, I make requests to many different websites.

 var http = require('http'); // http://mostpopularwebsites.net/1-50/ var sites = [ "www.google.com", "www.facebook.com", "www.youtube.com", "www.yahoo.com", "www.blogspot.com", "www.baidu.com", "www.live.com", "www.wikipedia.org", "www.twitter.com", "www.qq.com", "www.msn.com", "www.yahoo.co.jp", "www.sina.com.cn", "www.google.co.in", "www.taobao.com", "www.amazon.com", "www.linkedin.com", "www.google.com.hk", "www.wordpress.com", "www.google.de", "www.bing.com", "www.google.co.uk", "www.yandex.ru", "www.ebay.com", "www.google.co.jp", "www.microsoft.com", "www.google.fr", "www.163.com", "www.google.com.br", "www.googleusercontent.com", "www.flickr.com" ]; var server = http.createServer(function(req, res) { console.log("Got a connection."); if(req.url != "/") { console.log("But returning because the path was not '/'"); res.end(); return; } var counter = 0; for(var i = 1; i <= 30; i++) { http.get({ host: sites[i] }, function(index, host, r) { counter++; console.log("Response " + counter + " from # " + index + " (" + host + ")"); res.write("Response " + counter + " from # " + index + " (" + host + ")\n"); if(counter == 30) res.end(); }.bind(this, i, sites[i])); } console.log("Done with for loop."); }); server.listen(8000); 

I ran this program and visited the page very quickly in two different browsers (I also dropped my DNS cache, because the test worked too fast to get a good output otherwise). Here is the result:

 Got a connection. Done with for loop. Response 1 from # 8 (www.twitter.com) Response 2 from # 1 (www.facebook.com) Response 3 from # 12 (www.sina.com.cn) Response 4 from # 4 (www.blogspot.com) Response 5 from # 13 (www.google.co.in) Response 6 from # 19 (www.google.de) Response 7 from # 26 (www.google.fr) Response 8 from # 28 (www.google.com.br) Response 9 from # 17 (www.google.com.hk) Response 10 from # 6 (www.live.com) Response 11 from # 20 (www.bing.com) Response 12 from # 29 (www.googleusercontent.com) Got a connection. Done with for loop. Response 13 from # 10 (www.msn.com) Response 14 from # 2 (www.youtube.com) Response 15 from # 18 (www.wordpress.com) Response 16 from # 16 (www.linkedin.com) Response 17 from # 7 (www.wikipedia.org) Response 18 from # 3 (www.yahoo.com) Response 19 from # 15 (www.amazon.com) Response 1 from # 6 (www.live.com) Response 2 from # 1 (www.facebook.com) Response 3 from # 8 (www.twitter.com) Response 4 from # 4 (www.blogspot.com) Response 20 from # 11 (www.yahoo.co.jp) Response 21 from # 9 (www.qq.com) Response 5 from # 2 (www.youtube.com) Response 6 from # 13 (www.google.co.in) Response 7 from # 10 (www.msn.com) Response 8 from # 24 (www.google.co.jp) Response 9 from # 17 (www.google.com.hk) Response 10 from # 18 (www.wordpress.com) Response 11 from # 16 (www.linkedin.com) Response 12 from # 3 (www.yahoo.com) Response 13 from # 12 (www.sina.com.cn) Response 14 from # 11 (www.yahoo.co.jp) Response 15 from # 7 (www.wikipedia.org) Response 16 from # 15 (www.amazon.com) Response 17 from # 9 (www.qq.com) Response 22 from # 5 (www.baidu.com) Response 23 from # 27 (www.163.com) Response 24 from # 14 (www.taobao.com) Response 18 from # 5 (www.baidu.com) Response 19 from # 14 (www.taobao.com) Response 25 from # 24 (www.google.co.jp) Response 26 from # 30 (www.flickr.com) Response 20 from # 29 (www.googleusercontent.com) Response 21 from # 22 (www.yandex.ru) Response 27 from # 23 (www.ebay.com) Response 22 from # 19 (www.google.de) Response 23 from # 21 (www.google.co.uk) Response 24 from # 28 (www.google.com.br) Response 25 from # 25 (www.microsoft.com) Response 26 from # 20 (www.bing.com) Response 27 from # 30 (www.flickr.com) Response 28 from # 22 (www.yandex.ru) Response 28 from # 27 (www.163.com) Response 29 from # 25 (www.microsoft.com) Response 29 from # 26 (www.google.fr) Response 30 from # 21 (www.google.co.uk) Response 30 from # 23 (www.ebay.com) Got a connection. But returning because the path was not '/' 

As you can see, apart from the time period when I needed to press Alt+Tab Enter , the callbacks are completely confused - asynchronous, non-blocking I / O at its best.

[change]

As stated in mtomis, the number of maximum connections that you can open for each host is configured using the global http.globalAgent.maxSockets . Just set this number of concurrent connections that you want to handle for each host, and the problem you are observing disappears.

+8
source

Node.js has a restriction on client connections per host (by default 5 connections per host), as described here: http://nodejs.org/docs/v0.5.4/api/http.html#agent.maxSockets

The reason your second curling process freezes until the first one is complete is because the first process stops 30 requests, 5 of which can be processed at the same time, so the next 30 requests of the second process cannot be processed until until the first are completed. In your example, if you set http.globalAgent.maxSockets = 60; Then the calls will be processed simultaneously.

+5
source

Itโ€™s good that you donโ€™t actually create queries that, it seems to me, into something that can be returned. You have only one event handler, and it starts the loop all in a row.

Can you find where Ryan Dahl gave this conversation?

0
source

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


All Articles