微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么这个javascript在Node.js中阻塞?

我有以下使用Node.js的简单http服务器:
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);

当我在端口8000上卷入我的本地主机时,我确实得到了预期的结果:

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

但是当我在第一个进程运行时尝试从另一个终端卷入时,我看到控制台挂起并等待第一个进程完全完成,然后才开始接收相同的输出.

我的理解是,由于这是使用回调的异步代码,节点可以通过在事件循环的下一个滴答处理它们来同步处理多个请求.事实上,我甚至还观看过Ryan Dahl的视频,其中有一个类似于hello world的例子.我的代码中有什么东西可以阻止服务器阻塞?

解决方法

您的问题与阻止呼叫没有任何关系;这与您只能一次打开一定数量的连接到单个主机的事实有关.一旦达到最大打开连接数,对http.get的其他异步调用必须等到打开连接数再次下降,这在其他请求完成并触发其回调时发生.由于您创建新请求的速度超过了他们消耗的速度,因此您可能会看到阻塞的结果.

这是我为测试此程序而创建的程序的修改版本. (请注意,有一种更简单的方法解决您的问题,正如mtomis所示 – 更多内容如下所示.)我添加了一些console.log日志记录,因此更容易分辨处理内容的顺序;我还拒绝除/之外的所有请求,以便忽略favicon.ico请求.最后,我向许多不同的网站发出请求.

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

我运行这个程序,很快就在两个不同的浏览器中访问了该页面(我还刷新了我的DNS缓存,因为测试运行得太快,无法获得良好的输出).这是输出

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 '/'

正如你所看到的,除了我点击Alt Tab Enter的时间段之外,回调完全混合 – 最好的异步,非阻塞I / O.

[编辑]

正如mtomis所提到的,每个主机可以打开的最大连接数可以通过全局http.globalAgent.maxSockets进行配置.只需将其设置为您希望每个主机能够处理的并发连接数,您观察到的问题就会消失.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式。‌在聊深浅拷贝之前咱得了解一下js中的两种数据类型:
前言 今天复习了一些前端算法题,写到一两道比较有意思的题:重建二叉树、反向输出链表每个节点 题目 重建二叉树: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 {1,2,4,7,3,5,6,8} 和中序遍历序列 {
最近在看回JavaScript的面试题,this 指向问题是入坑前端必须了解的知识点,现在迎来了ES6+的时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,所以刚好总结一下JavaScript中this指向的问题。
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高