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

想象一下,在由几个不同的小部件组成的应用程序中。 触发事件时,窗口小部件会清除其当前数据,执行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); } } } 

这是上面代码的JSFiddle

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

Chrome http://sofzh.miximages.com/jquery/chrome.png

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

IE http://sofzh.miximages.com/jquery/ie.png

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

IE Fiddler http://sofzh.miximages.com/jquery/ie1.png

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

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

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

IE网络http://sofzh.miximages.com/jquery/ie-dev-tools.png

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

IE First Request http://sofzh.miximages.com/jquery/ie-timings.png

为什么会这样?

有关更详细的说明,请参阅我的博文 。

由于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") ),然后添加100个元素,而容器未附加到DOM,最后将整个容器添加到DOM。 这将在单个绘制事件中添加这100个元素,这更便宜,并且由于任务优先级划分,其他诸如AJAX之类的东西应该在更短的时间内执行。

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

您应该在SO中查看此其他问答: JavaScript如何在后台处理AJAX响应?

当浏览器“空闲”时,两个浏览器都会进行Ajax调用。 Chrome在操作DOM方面要比IE好得多,它似乎只能立即调用Ajax。

但是,如果删除此行:

 el.removeChild(child); 

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

当Chrome要求创建然后删除相同的节点时,Chrome可能会进行一些优化。 这可能被认为是一个“边缘案例”,Chrome恰好比IE更好。

无论如何,在multithreadingJavaScript出现之前,代码优化是处理这种情况的最佳方式。