为什么IE等待调用堆栈为空以发送POST AJAX请求?

时间:2014-08-13 17:30:21

标签: 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: ‘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);
        }
    }
}

Here is a JSFiddle of the code above

如果你打开Fiddler并在Chrome中运行它,你会发现AJAX请求很快就完成了。

Chrome http://zgardner.us/wp-content/uploads/2014/08/chrome.png

但是如果你在IE中做同样的事情(在10,11,12预览中测试过),你会发现请求需要更长的时间:

IE http://zgardner.us/wp-content/uploads/2014/08/ie.png

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

IE Fiddler http://zgardner.us/wp-content/uploads/2014/08/ie1.png

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

这仅适用于POST AJAX请求。 GET的ClientBeginRequest和ClientDoneRequest总是在几毫秒之内。

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

IE Network http://zgardner.us/wp-content/uploads/2014/08/ie-dev-tools.png

如果你检查一个单独的请求,你可以在第二个开始,也就是它发送请求正文时,花了4.32秒:

IE First Request http://zgardner.us/wp-content/uploads/2014/08/ie-timings.png

为什么会这样?

有关更详细的说明,请参阅my blog post

2 个答案:

答案 0 :(得分:4)

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

Web浏览器使用执行队列实现异步。有一个线程,它从UI和AJAX(和其他任务源)参加排队的任务。也就是说,它只能一次发生一次操作。

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

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

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

另外,我不确定你是否知道Fiddler减速请求(它是一个调试器,有性能损失)。

您应该在SO:How does JavaScript handle AJAX responses in the background?

中查看此其他问答

答案 1 :(得分:0)

当浏览器闲置时,两个浏览器都会进行Ajax调用。&#34; Chrome在操作DOM方面要比IE好得多,只有似乎才能立即调用Ajax。

但是,如果删除此行:

el.removeChild(child);

...你会注意到Chrome需要大约。进行第一次Ajax呼叫的时间要长四倍,然后是快速连续的九次呼叫。

当Chrome要求创建然后移除相同节点时,Chrome可能会进行一些优化。这可以被视为边缘情况,&#34;哪个Chrome比IE更好。

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