Jquery 为什么IE要等到调用堆栈为空时才发送POST AJAX请求?

Jquery 为什么IE要等到调用堆栈为空时才发送POST AJAX请求?,jquery,ajax,internet-explorer,Jquery,Ajax,Internet Explorer,想象一下由几个不同的小部件组成的应用程序。当触发事件时,小部件清除当前数据,执行AJAX请求,然后在响应返回时输入新信息 以下是触发该事件时发生的情况的简化示例: for (var i = 0; i < 10; i++) { // Do an AJAX post $.ajax(document.location.href, { data: { name: ‘Zach Gardner’ }, method

想象一下由几个不同的小部件组成的应用程序。当触发事件时,小部件清除当前数据,执行AJAX请求,然后在响应返回时输入新信息

以下是触发该事件时发生的情况的简化示例:

for (var i = 0; i < 10; i++) {
    // Do an AJAX post
    $.ajax(document.location.href, {
        data: {
            name: ‘Zach Gardner’
        },
        method: ‘POST’
    });
    // Do some expensive DOM stuff
    for (var j = 0; j < 100; j++) {
        var el = document.createElement(‘div’);
        document.body.appendChild(el);
        for (var k = 0; k < 100; k++) {
            var child = document.createElement(‘div’);
            el.appendChild(child);
            el.removeChild(child);
        }
    }
}
for(变量i=0;i<10;i++){
//写一篇AJAX文章
$.ajax(document.location.href{
数据:{
姓名:“扎克·加德纳”
},
方法:“发布”
});
//做一些昂贵的事情
对于(var j=0;j<100;j++){
var el=document.createElement('div');
文件.正文.附件(el);
对于(var k=0;k<100;k++){
var child=document.createElement('div');
el.儿童(child);
el.removeChild(儿童);
}
}
}

如果打开Fiddler并在Chrome中运行它,您会发现AJAX请求完成得相当快


(来源:)

但是如果您在IE中执行相同的操作(在10、11、12预览中测试),您会注意到请求需要更长的时间:


(来源:)

我们发现,当jQuery执行对xhr的send方法的调用时,IE将创建请求。但它会一直保留请求,直到调用堆栈被清空


(来源:)

请注意ClientBeginRequest和ClientDoneRequest之间的显著延迟。我们发现ClientDoneRequest总是在线程结束后的几毫秒内

这只发生在AJAX请求之后。获取的ClientBeginRequest和ClientDoneRequest之间的间隔总是在几毫秒之内

另外,请注意,IE的开发工具也会出现此问题:


(来源:)

如果检查单个请求,则可以在第二次启动(即发送请求正文时)花费4.32秒:


(来源:)

为什么会这样


请参阅以获得更详细的解释。

由于Internet Explorer的源代码不是免费提供的,因此只有IE开发人员才能更详细地回答您的问题

Web浏览器使用执行队列实现异步性。只有一个线程,它处理来自UI和AJAX(以及其他任务源)的排队任务。也就是说,它只能同时发生一次操作

另一方面,UI优先于任何其他任务,因此,DOM操作应该在AJAX调用之前执行。当您发送AJAX请求时,发送请求可能需要很短的CPU时间,但是如果您做了大量的UI工作,那么结束整个AJAX请求可能需要更长的时间,因为在优先级方面,
UI>AJAX


您在问题中描述的案例是Internet Explorer中的一个实现细节。Chrome和Firefox在任务优先级方面可能工作得更好,但无论如何,我不认为在发送大量AJAX请求的同时,您会尝试同时附加100个DOM元素。您需要优化代码,而不是期望您的Web浏览器优化学术/边缘案例

例如,您可能不会将100个DOM元素逐个添加到文档元素中。您可以创建一个容器(即
document.createElement(“div”)
),然后在容器未连接到DOM时添加100个元素,最终将整个容器添加到DOM。这将在一个绘画事件中添加这100个元素,这更便宜,而且由于任务优先级的原因,其他类似AJAX的东西应该在更短的时间内执行

另外,我不确定您是否知道Fiddler会降低请求的速度(这是一个调试器,会影响性能)


你应该看看这里的另一个问答:

两个浏览器在浏览器“空闲”时都会进行Ajax调用。Chrome比IE更擅长处理DOM,因此它看起来只是会立即进行Ajax调用

但是,如果删除此行:

el.removeChild(child);
。。。您会注意到,Chrome第一次调用Ajax所需的时间大约是它的四倍,然后是连续九次调用

当要求Chrome创建并删除同一个节点时,它可能会进行一些优化。这可能被认为是一个“边缘案例”,而Chrome恰好比IE更擅长于此


无论如何,在多线程JavaScript出现之前,代码优化是我们处理这种情况的最佳方式。

您测试的是哪个IE版本?我会更加谨慎。你的博客帖子说公司应该知道这个问题,而我不认为公司会根据你的示例代码的概念来编程他们的Web应用程序@Powerlord我已经在IE10、11和12开发者预览版中对此进行了测试。你文章中的链接似乎不再有效。没有决心做任何事。这很遗憾,因为我认为我遇到了与你描述的相同的问题,但我无法证实。请考虑更新与一些公共形象托管服务的链接。感谢“需要优化代码的是您,而不是期望您的Web浏览器优化学术/边缘案例。”如果我使用普通语言执行异步操作(例如,创建新线程),则该操作的执行独立于当前线程。基本假设是AJAX请求是异步的,应该以异步方式发送到服务器。此外,为什么IE会立即发送GET,而等到最后才发送邮件?“另外,我不确定你是否知道Fiddler会减慢请求速度”我们使用了TCPview,并且看到了相同的行为。@ZachGardner你可以争辩,但是Web浏览器,无论是IE、Chrome还是Firefox,都是单线程的!!!Web开发方法中的非同步性是一个单线程的出列工作。@ZachGardner想想看,在没有同步的情况下,从AJAX回调访问DOM是多么容易