流行的浏览器中允许同时进行多少个AJAX(XmlHttpRequest)请求?

378
在Firefox 3中,每个域名可以发起6个XmlHttpRequest请求,即使是在任何标签页上对同一域的第7个请求也会被排队等待,直到其中一个6个请求完成为止。
其他主流浏览器的数字是多少?
此外,是否有方法可以绕过这些限制,而不需要让我的用户修改他们的浏览器设置?例如,jsonp请求的数量是否有限制(使用脚本标记注入而不是XmlHttpRequest对象)?
背景:我的用户可以从网页向服务器发起XmlHttpRequest请求,要求服务器在远程主机上运行ssh命令。如果远程主机宕机,则ssh命令需要几分钟才能失败,最终阻止我的用户执行任何进一步的命令。

1
谢谢Bob,这是我计划解决这个问题的两种方法之一--我考虑在问题中提到它,但决定这是离题了。(另一种方法是让我控制的服务器超时ssh请求。) - Michael Gundlach
1
我认为你已经得到了答案...可以非常安全地假设Safari和Chrome支持至少2个,因此您始终可以假设为2。 - Rex M
1
在Windows Vista上使用Chrome 2.0.172.28,我得到了6个并发连接。 - Callum
2
我刚找到了这个网页http://www.stevesouders.com/blog/2008/03/20/roundup-on-parallel-connections/ ,其中提供了更多数据并进行了讨论。 - David Johnstone
在Firefox中,您可以在“about:config”下找到“network.http.max-connections-per-server”,并且还有一个“max-persistent-connections-per-server”的姐妹值,用于获取最大连接数。 - Marc B
显示剩余3条评论
9个回答

149

一个增加并发连接数的技巧是从不同的子域名托管您的图像。这些将被视为单独的请求,每个域名将受到并发最大限制。

IE6、IE7 - 限制为2。如果您拥有宽带,则IE8为6,如果是拨号连接,则为2。


4
不,限制是针对域名设定的。因此,如果您除了网站之外还有一个子域名,理论上可以将 FF 连接数提高到 12。 - Bob
9
哇,这是个好技巧。这也解释了为什么地图引擎的瓦片服务器会创建一些虚假的子域名(通常是类似于maps1.whatever.com, maps2.whatever.com, maps3.whatever.com),以加快速度。 - meawoppl
1
浏览器会在整个组加载完成之前等待吗,然后才继续进行下一组请求;还是会保持并发请求的堆栈满,并用一个新任务替换已完成的任务? - AMember
2
@AMember,浏览器始终保持其允许的最大并发ajax数量。如果您想看到实际效果,请尝试我的下面的答案。 - Saic Siquot
1
希望能够更新以适应更新的浏览器。 - Tom
显示剩余4条评论

101

Browserscope 的网络测试结果将为您提供流行浏览器的每个主机名的连接数最大连接数。该数据是通过对“野外”用户进行测试而收集的,因此始终保持最新。


3
很遗憾,那看起来一点也不新。 - Dave Lawrence
@DaveLawrence 我刚刚检查了一下,完整的数据集似乎包含了Chrome 60和61,这是相当更新的版本。 - Simon East
1
有没有其他替代品可以测试这个,看起来工具不再托管了。 - felickz

26

对于IE6 / IE7,可以通过修改注册表来调整并发请求的数量。以下是将其设置为每个四个的方法。

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings]
"MaxConnectionsPerServer"=dword:00000004
"MaxConnectionsPer1_0Server"=dword:00000004

16
OP说“不需要让我的用户修改他们的浏览器设置”。但这样做并不切实际,因为每个客户端都需要进行此操作。 - Razort4x
23
这仍然是一个非常有用的知识点,与此问题相关。也许把它发布为评论而不是答案会更好? - JD Smith

7

我刚刚在www.browserscope.org上查阅了相关信息,发现IE9和Chrome 24浏览器可以同时向同一域名建立6个连接,同时也可以向多个域名建立17个连接。


6

我编写了一个单文件AJAX测试器。享受它吧!

只是因为我与我的托管提供商遇到了问题。

<?php /*

Author:   Luis Siquot
Purpose:  Check ajax performance and errors
License:  GPL
site5:    Please don't drop json requests (nor delay)!!!!

*/

$r = (int)$_GET['r'];
$w = (int)$_GET['w'];
if($r) { 
   sleep($w);
   echo json_encode($_GET);
   die ();
}  //else
?><head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">

var _settimer;
var _timer;
var _waiting;

$(function(){
  clearTable();
  $('#boton').bind('click', donow);
})

function donow(){
  var w;
  var estim = 0;
  _waiting = $('#total')[0].value * 1;
  clearTable();
  for(var r=1;r<=_waiting;r++){
       w = Math.floor(Math.random()*6)+2;
       estim += w;
       dodebug({r:r, w:w});
       $.ajax({url: '<?php echo $_SERVER['SCRIPT_NAME']; ?>',
               data:    {r:r, w:w},
               dataType: 'json',   // 'html', 
               type: 'GET',
               success: function(CBdata, status) {
                  CBdebug(CBdata);
               }
       });
  }
  doStat(estim);
  timer(estim+10);
}

function doStat(what){
    $('#stat').replaceWith(
       '<table border="0" id="stat"><tr><td>Request Time Sum=<th>'+what+
       '<td>&nbsp;&nbsp;/2=<th>'+Math.ceil(what/2)+
       '<td>&nbsp;&nbsp;/3=<th>'+Math.ceil(what/3)+
       '<td>&nbsp;&nbsp;/4=<th>'+Math.ceil(what/4)+
       '<td>&nbsp;&nbsp;/6=<th>'+Math.ceil(what/6)+
       '<td>&nbsp;&nbsp;/8=<th>'+Math.ceil(what/8)+
       '<td> &nbsp; (seconds)</table>'
    );
}

function timer(what){
  if(what)         {_timer = 0; _settimer = what;}
  if(_waiting==0)  {
    $('#showTimer')[0].innerHTML = 'completed in <b>' + _timer + ' seconds</b> (aprox)';
    return ;
  }
  if(_timer<_settimer){
     $('#showTimer')[0].innerHTML = _timer;
     setTimeout("timer()",1000);
     _timer++;
     return;
  }
  $('#showTimer')[0].innerHTML = '<b>don\'t wait any more!!!</b>';
}


function CBdebug(what){
    _waiting--;
    $('#req'+what.r)[0].innerHTML = 'x';
}


function dodebug(what){
    var tt = '<tr><td>' + what.r + '<td>' + what.w + '<td id=req' + what.r + '>&nbsp;'
    $('#debug').append(tt);
}


function clearTable(){
    $('#debug').replaceWith('<table border="1" id="debug"><tr><td>Request #<td>Wait Time<td>Done</table>');
}


</script>
</head>
<body>
<center>
<input type="button" value="start" id="boton">
<input type="text" value="80" id="total" size="2"> concurrent json requests
<table id="stat"><tr><td>&nbsp;</table>
Elapsed Time: <span id="showTimer"></span>
<table id="debug"></table>
</center>
</body>
编辑:
r代表行,w代表等待时间。
当您最初按下开始按钮时,JavaScript会启动80个(或任何其他数字)并发的ajax请求,但众所周知它们被浏览器缓存。此外,它们以并行方式请求服务器(限制为某个特定数量,这是问题的事实)。在这里,请求在服务器端解决,具有随机延迟(由w确定)。在开始时间,计算解决所有ajax调用所需的所有时间。当测试完成后,您可以看到它是否花费了总时间的一半、三分之一、四分之一等,从中减去了对服务器调用的并行性。这不是严格的,也不是精确的,但是实时查看ajax调用如何完成(查看传入的交叉信息)非常简单自包含的脚本来显示ajax基础知识。
当然,这假设服务器端没有引入任何额外的限制。
最好与Firebug网络面板(或您的浏览器的等效工具)一起使用。

所以我确认,FF3可以同时发起最多六个并发请求。 - Saic Siquot
你能否解释一下这里做了什么?r和w是什么?如果提供分析结果的截图会更好。 - Royi Namir

6

我写了自己的测试代码,在stackoverflow上测试过,结果良好。告诉我chrome/FF可以实现6。

var change = 0;
var simultanius = 0;
var que = 20; // number of tests

Array(que).join(0).split(0).forEach(function(a,i){
    var xhr = new XMLHttpRequest;
    xhr.open("GET", "/?"+i); // cacheBust
    xhr.onreadystatechange = function() {
        if(xhr.readyState == 2){
            change++;
            simultanius = Math.max(simultanius, change);
        }
        if(xhr.readyState == 4){
            change--;
            que--;
            if(!que){
                console.log(simultanius);
            }
        }
    };
    xhr.send();
});

它适用于大多数可以在不同时间触发readystate更改事件的网站(也称为刷新)。

我注意到在我的node.js服务器上,我必须输出至少1025个字节才能触发事件/刷新。否则,当请求完成时,事件将同时触发所有三个状态,因此这是我的后端:

var app = require('express')();

app.get("/", function(req,res) {
    res.write(Array(1025).join("a"));
    setTimeout(function() {
        res.end("a");
    },500);
});

app.listen(80);

更新

我注意到,如果您同时使用xhr和fetch api,现在可以最多有2倍的请求。

var change = 0;
var simultanius = 0;
var que = 30; // number of tests

Array(que).join(0).split(0).forEach(function(a,i){
    fetch("/?b"+i).then(r => {
        change++;
        simultanius = Math.max(simultanius, change);
        return r.text()
    }).then(r => {
        change--;
        que--;
        if(!que){
            console.log(simultanius);
        }
    });
});

Array(que).join(0).split(0).forEach(function(a,i){
    var xhr = new XMLHttpRequest;
    xhr.open("GET", "/?a"+i); // cacheBust
    xhr.onreadystatechange = function() {
        if(xhr.readyState == 2){
            change++;
            simultanius = Math.max(simultanius, change);
        }
        if(xhr.readyState == 4){
            change--;
            que--;
            if(!que){
                document.body.innerHTML = simultanius;
            }
        }
    };
    xhr.send();
});


我的上面显示19,是它坏了吗? - PauAI
Firefox 开发者版 57.0b12 显示 2。 - AnthonyB

6
根据HttpWatch博客上的IE 9 - What's Changed?,当使用VPN时,IE9仍然有2个连接限制。

使用VPN仍会影响IE 9性能

我们之前报道过,在使用VPN连接时,IE8最大并发连接数被缩减。即使浏览器流量不经过该连接也会发生这种情况。

不幸的是,IE9也受到VPN连接的影响:


0

我相信浏览器对于同一域名的并发http请求有一个最大数量限制,这个数量大约在4-8个请求之间,具体取决于用户的设置和浏览器。

你可以将请求设置到不同的域名上,这可能是可行的,也可能不可行。雅虎的工程师在这方面做了很多研究,你可以阅读相关内容(这里)。请记住,每添加一个新域名都需要进行DNS查找。YSlow的工程师建议使用2到4个域名来实现并行请求和DNS查找之间的良好平衡,尽管这主要关注页面加载时间,而不是后续的AJAX请求。

我可以问一下为什么你想发起这么多请求吗?浏览器限制同一域名的请求次数是有充分理由的。如果可能的话,最好将请求捆绑在一起。


1
我的XmlHttpRequests不能像你建议的那样跨越不同的域,因为存在同源策略。也许这是使用jsonp绕过此问题的一个论点。该页面是多台计算机的命令和控制面板;因此,每个用户请求的执行都会产生一个请求。 - Michael Gundlach

0

HTTP2上的Ajax请求怎么样?目前浏览器还不支持。 - RamPrakash
@RamPrakash,那不是真的。您可以在Chrome的网络选项卡中看到h2协议... 这显示了http2连接。 - Raskolnikov
这是针对静态文件的,不适用于Ajax请求。你能否给我展示一个链接看看?目前这是浏览器的一个限制。 - RamPrakash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接