发送XHR时Web工作者并不真正并发?

时间:2016-10-18 14:40:50

标签: javascript xmlhttprequest web-worker

这个问题在一个庞大而复杂的应用程序中引起了深刻的印象,但它可以在一个简单的用例中重现:如果主浏览器线程忙, 由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);

1 个答案:

答案 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);