这个问题在一个庞大而复杂的应用程序中引起了深刻的印象,但它可以在一个简单的用例中重现:如果主浏览器线程忙, 由Web工作者发送的XHR将阻塞,直到主浏览器线程空闲,几乎就像工作者是一个挂起0ms超时的正常功能一样, 等待主线程的转向。实际上并不是发生了什么:正在进行并发,我们可以从时间上看出来 日志条目,但似乎实际发送XMLHttpRequest只能在主Javascript线程空闲时完成。
起初,我们认为这种行为仅限于Internet Explorer,但事实上它只是出现这种情况,因为IE在我们的特定情况下要慢得多 用例,因此主浏览器线程保持忙碌的时间更长。这种非并发行为实际上存在于我尝试过的所有浏览器中(IE, Chrome,Firefox)。浏览器的行为并不完全相同:有时它们会阻塞open()调用,有时它们会阻塞send(),有时会阻塞 他们声称send()及时完成,但使用像Fiddler这样的HTTP调试器显示数据实际上并未发送到 服务器,直到主浏览器线程完成其长时间运行的任务。
所以我希望有人可以告诉我为什么会这样,并且如果有任何方法可以让网络工作者以正确的并发方式发送XHR。顺便说一句,我 已经知道整个问题的症结在于主要的Javascript线程有多繁忙,所以请不要告诉我解决这个问题;我们正在工作 同样,但长期运行的任务是客户应用程序中极其复杂的基于JS的UI的重排,因此我们受到限制 在那里我们能做什么。
这个责备案例显示了问题:
<html>
<body>
<div id="test"></div>
<script>
worker = new Worker('worker.js');
// Wait for 2 seconds to be as sure as we can be that it has downloaded and installed the worker code
setTimeout(proceed, 2000);
function proceed() {
worker.postMessage("");
console.log("Message sent to worker: " + new Date().getTime());
// Now tie up the JS thread
setTimeout(function() {
console.log("Started crazy pointless loop: " + new Date().getTime());
for (var i = 0; i < 500000; i++) {
var j = i / 17,
k = j * j,
l = k / 123;
document.getElementById("test").innerHTML = "l = " + l;
}
console.log("Finished crazy pointless loop: " + new Date().getTime());
}, 0);
}
</script>
</body>
</html>
和worker.js文件:
addEventListener('message', function(e) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState < 4) return;
console.log("Response received: " + new Date().getTime());
}
console.log("Ready to open XHR: " + new Date().getTime());
xhr.open("GET", "dummy.html?nocache=" + new Date().getTime(), true);
console.log("XHR opened: " + new Date().getTime());
xhr.send();
console.log("XHR sent: " + new Date().getTime());
}, false);
答案 0 :(得分:1)
你最好从工作人员同步发送XHR,因为你已经在一个单独的线程中运行了:
addEventListener('message', function(e) {
var xhr = new XMLHttpRequest();
console.log("Ready to open XHR: " + new Date().getTime());
xhr.open("GET", "dummy.html?nocache=" + new Date().getTime(), false); // false makes it synchronous
console.log("XHR opened: " + new Date().getTime());
xhr.send();
console.log("Response received: " + new Date().getTime());
}, false);