Javascript Chrome中的主线程阻止Web Worker

Javascript Chrome中的主线程阻止Web Worker,javascript,multithreading,google-chrome,xmlhttprequest,web-worker,Javascript,Multithreading,Google Chrome,Xmlhttprequest,Web Worker,我有一本书。我希望定期使用它进行网络请求。我特别想做的一件事是,即使主JS执行线程被阻塞(例如被window.alert阻塞),也要发出这些请求。我用的是Chrome38 但是,当我尝试在worker中发出网络请求时,请求似乎被UI线程阻止。下面是一个人为的例子来说明这个问题: base.js: var worker = new Worker("/worker.js"); setTimeout(function() { console.log("begin blocking");

我有一本书。我希望定期使用它进行网络请求。我特别想做的一件事是,即使主JS执行线程被阻塞(例如被window.alert阻塞),也要发出这些请求。我用的是Chrome38

但是,当我尝试在worker中发出网络请求时,请求似乎被UI线程阻止。下面是一个人为的例子来说明这个问题:

base.js:

var worker = new Worker("/worker.js");

setTimeout(function() {
    console.log("begin blocking");
    var startDt = new Date();
    var blockPeriod = 5000;
    var a;
    // Obviously we'd never actually do this, but this while loop
    // is a convenient way to create the problem case (a blocked main
    // thread).
    while ((new Date() - startDt) < blockPeriod) {
        a = 0;
    }
    console.log("stop blocking");
}, 3000);
我看到的结果是,我们看到成功的HTTP请求持续了三秒,直到阻塞开始。此时,在阻塞结束之前,我们看不到任何记录到控制台的内容,此时我们看到五个“发送请求间隔”,然后是五个响应日志,如下所示:

Send request interval
{"pong": true}
Send request interval 
{"pong": true} 
Send request interval
{"pong": true}
Send request interval
{"pong": true}
begin blocking
stop blocking
5x Send request interval
5x {"pong": true}
Send request interval
{"pong": true}
我在服务器日志中还看到,在阻塞时间内没有发出任何请求,然后在阻塞期结束时,这五个请求几乎同时收到

考虑到“发送请求间隔”在一行中出现了五次,工作进程显然在继续执行:如果没有,它将无法完成下一次迭代的排队。我还发现,如果我通过触发window.alert(而不是在循环中旋转)进行阻止,我会以1秒的间隔从
sendRequest
的开头获取日志消息,然后在停止阻止后立即获取大量响应处理程序日志消息

在Firefox中,后台线程在这种情况下似乎完全停止了(我没有在阻塞期间得到同样的五个请求排队)。然而,在这种情况下,我只针对Chrome(我最终想要使用甚至在Firefox Workers中都不起作用的WebSocket),所以我对此并不感兴趣

所有这些加在一起,使我相信Web Workers中有一些活动类被生成线程阻止,而有些则没有(我最初在WebSocket中看到了相同的行为)。具体来说,我想知道(如果有人知道):

  • Chrome中的主线程阻止了哪些工人活动
  • 有办法解决这个问题吗?我非常希望能够在Worker中建立WebSocket连接,然后继续来回PING/PONG,即使某些东西(例如警报/确认)确实阻止了主线程
  • 这都是胡说八道吗?我只是在做傻事吗

  • 你的观察是正确的。当UI线程被阻止时,不会调度网络调用

    更糟糕的是,Chrome拥有最好的性能。当工作线程在UI线程被阻止时发出XHR请求时:

    • Chrome:所有请求都已排队。在UI线程解除阻止之前,浏览器不会实际发出请求。从好的方面来看,辅助线程仍然可以自由运行
    • Firefox:
      newXMLHttpRequest()
      阻塞,直到UI线程解锁
    • IE:
      xhr.open()
      阻塞,直到UI线程解除阻塞
    幸运的是,Chrome不会导致工作线程停止并等待(即使它不会获取任何数据),而Firefox和IE会在您尝试发出XHR请求时导致工作线程在UI线程上等待


    没有办法解决这个问题;你需要浏览器代表你提出请求。我没有对WebSocket做过任何测试,但是即使UI线程被阻塞,它们也可能会传递事件。在最坏的情况下,收到的消息将排队等待UI线程解锁。

    如果有人无意中发现此行为,此行为将在2015年2月的Blink中被确认为错误(根据“错误”的松散定义为“行为不正常”):


    我也遇到了同样的问题,一个Web工作者执行了一种保持活动状态的操作:它定期ping服务器,以通知页面仍然处于活动状态。我还在worker中使用console.log,但我确信这不是原因

    经过一些调查后,我可以说这个问题可以解决两种不同的情况:

  • 一个长时间的UI操作正在阻塞主线程,工作线程的请求不会被执行。这是heliotrope演示的示例。截至2018年9月,该问题仅出现在Firefox和IE上,因为当主线程被阻塞时,Chrome和Edge可以正确处理worker上的活动 为了解决这个问题,我正在考虑在开始任何长时间操作之前向服务器发送一个特殊的ping,通知他在操作完成之前不会收到我的任何消息

  • 主线程正在执行一个长时间异步ajax调用,工作线程的请求将排队。服务器上的某些设置阻止多个ajax调用并行运行:其他请求排队等待,直到第一个ajax调用完成。问题是特定于服务器的,因此它不特别依赖于任何浏览器
  • 在我的例子中,这个问题是由于ASP.NET会话状态锁定造成的:ASP.NET管道不会同时处理属于同一会话的请求,而是对它们进行排队,并串行执行它们。这里有一个详细的链接:。


    将控制器的会话状态标记为只读将解决此问题,而在Web.config()中完全禁用会话状态将极大地提高整个应用程序的性能。

    是的,在发出
    警报期间它将被禁用。
    :-)Bergi,感谢您的回复。然而,web workers的整个想法是,他们在后台线程中操作,不会干扰UI(bobince甚至在您链接的答案中提到了这一警告)。在某种程度上,情况显然是这样的:我上面概述的示例表明,在某种程度上,即使主线程被阻塞,它们也会被执行。我的大问题是,主线程阻塞和不阻塞之间的界限在哪里。“非阻塞不一定意味着并发”。来源文章:@sergiolius,我不确定我是否明白。那篇文章似乎声称网络工作者是一个
    Send request interval
    {"pong": true}
    Send request interval 
    {"pong": true} 
    Send request interval
    {"pong": true}
    Send request interval
    {"pong": true}
    begin blocking
    stop blocking
    5x Send request interval
    5x {"pong": true}
    Send request interval
    {"pong": true}