Web Worker 在 Chrome 中被主线程阻止

2024-01-01

我有一个网络工作者 https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/basic_usage。我希望用它定期发出网络请求。我特别想要的一件事是即使主 JS 执行线程被阻塞(例如被 window.alert),也可以发出这些请求。我使用的是 Chrome 38。

但是,当我尝试在工作线程中发出网络请求时,请求似乎被 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);

工人.js:

var requestInterval = 1000;

var sendRequest = function() {
    console.log("Send request interval");

    var request = new XMLHttpRequest();
    request.open("GET", "/ping", true);

    request.onload = function() {
        if (request.status === 200){
            console.log(request.responseText)
        } else {
            console.log(request.status)
        }
    };

    request.onerror = function() {
        console.log("error")
    };

    request.send();

    setTimeout(sendRequest, requestInterval);
}

sendRequest();

我看到的结果是,我们看到成功的 HTTP 请求持续三秒钟,直到阻塞开始。此时,在阻塞结束之前我们看不到任何记录到控制台的内容,此时我们会看到 5 个“发送请求间隔”,后面跟着 5 个响应日志,如下所示:

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 来阻止而不是循环旋转,我会从开头获取日志消息sendRequest以 1 秒为间隔,然后在我停止阻塞后立即批量获取响应处理程序日志消息。

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

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

  1. Chrome 中哪些 Worker 活动被主线程阻止?
  2. 有办法解决这个问题吗?我非常希望能够在 Worker 中建立 WebSocket 连接,然后继续来回 PING/PONG,即使某些内容(例如警报/确认)确实阻塞了主线程。
  3. 这都是废话吗,我只是在做傻事吗?

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

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

  • Chrome:所有请求都排队。在 UI 线程解除阻塞之前,浏览器不会真正发出请求。从好的方面来说,工作线程仍然可以自由运行。
  • 火狐浏览器:new XMLHttpRequest()阻塞直到 UI 线程解除阻塞。
  • IE: xhr.open()阻塞直到 UI 线程解除阻塞。

幸运的是,Chrome 不会导致工作线程停止并等待(即使它不会获取任何数据),但当您尝试发出 XHR 请求时,Firefox 和 IE 将导致工作线程在 UI 线程上等待。

没有办法解决这个问题;您有义务让浏览器代表您发出请求。我还没有对 WebSockets 进行过任何测试,但是它们may即使 UI 线程被阻塞,也会传递事件。在最坏的情况下,收到的消息将排队直到 UI 线程解除阻塞。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Web Worker 在 Chrome 中被主线程阻止 的相关文章

随机推荐

  • 如何在 Azure 函数中调用另一个函数

    我写了3个函数如下 在数据库中创建用户 从数据库获取用户 流程用户 在 3 函数中 我将调用 2 函数来让用户使用 Azure 函数 url 如下所示 https hdidownload azurewebsites net api getu
  • 有意在自身之上运行 Worksheet_Change

    Skip my rambling narrative by scrolling down to tldr https stackoverflow com questions 51298646 running worksheet change
  • 将 Android 调试器附加到使用我不拥有的 Eclipse 项目构建的进程

    我想调试 Android 应用程序的一部分 但我没有用于构建它的原始 Eclipse 项目 我已经建立了一个 jar实现 Android Activity 的文件 我使用Eclipse来开发和调试它 并且javac jar建立 jar与适当
  • 如何避免 R 中的循环:从列表中选择项目

    我可以使用循环来解决这个问题 但我正在尝试用向量来思考 这样我的代码将更加 R 风格 我有一份名单 格式为名字 姓氏 我想从这个列表中得到一个只有名字的单独列表 我似乎不知道如何做到这一点 以下是一些示例数据 t lt c bob smit
  • mysql_connect (localhost / 127.0.0.1) 在 Windows 平台上速度慢

    我使用的是 Windows 7 Apache 2 PHP 5 MySQL 5 它们都在同一台机器上 我发现一个有趣的问题 我有以下代码 sql select from user1 conn mysql connect localhost r
  • 如何将 UserDefinedType(UDT) 与 Spring Data Cassandra 用于 List

    我在 cql 中创建了一个名为 widgetData 的 UDT 我有一个名为 widgetData 的相应 POJO 类 我想在另一个域 POJO 类中使用它作为 List 应该使用什么样的注释来做到这一点 Table dashboard
  • Django动态表单示例

    我有一个在 Django 中创建动态表单的简单要求 我已经看过很多示例 但它们似乎不完整 或者需要比我更广泛的 Python 和 Django 知识 没有显示如何调用示例的动态部分 这是带有 Q1 和 Q2 的表单类 我在表单上放置一个按钮
  • 在 AndroidManifest.xml 中设置 screenOrientation 不起作用

    我有一个简单的 hello world Android 测试项目 在我的 AndroidManifest xml 中 我已经设置 android screenOrientation portrait android configChange
  • 布尔“not”函数的函数组合(不是布尔值)

    我正在 TS 中工作 但会在下面显示 tsc gt ES6 代码 我有一个函数 isDigit 如果字符代码在数字 0 9 范围内 则该函数返回 true 该函数 isDigit 必须作为参数传递到高阶函数中 const isDigit c
  • 如何从文件中绘制对象(矩形)

    在 gnuplot 中我可以通过绘制一个矩形 set object rect from x0 y0 to x1 y1 如何从文件中读取坐标x0 x1 y0 y1 一种方法是将设置矩形的代码行放入一个单独的文件中 并从 gnuplot 脚本中
  • JAX-RS 响应的 HTTP 状态为 500,而不是 HTTP 状态 400

    有时 JAR RS 客户端会发送错误的语法请求正文 服务器应响应HTTP 状态 400 错误请求 https www rfc editor org rfc rfc7231 section 6 5 1 但它的响应是HTTP 状态 500 内部
  • 在 Vim 中计算出现次数而不标记缓冲区已更改

    为了知道当前缓冲区中某个模式存在多少次 我这样做 s pattern here pattern here g 它给出了模式出现的次数 但显然很麻烦 并且还具有设置 已更改 状态的副作用 有没有更优雅的计数方式 为了避免替换 请将第二个模式留
  • 陷入 C# 正则表达式困境

    我的数据库中的字段中包含以下文本 quote 5a7b87febe mr smith This is some text This is more text on another line quote 5a7b87febe 我正在尝试构建一
  • 将 Java 对象转换为 XML 时的 XStream 撇号问题

    我在用com thoughtworks xstream XStream生成 xml 字符串 我将对象解析为 xstream toXML方法 我根据我需要的方式获得 xml 输出
  • ggplot 更改 x 轴标签而不更改基础数据

    我在 x 轴上绘制小平面和离散数据 如何更改 x 轴标签without改变底层数据 IE 而不是标签阅读 a b c d 他们应该阅读 Lab 1 Lab 2 Lab 3 Lab 4 df lt data frame x factor re
  • 邮件枪 - 401 禁止

    我尝试使用 mailgun 发送电子邮件 我使用 node js nest js 这是我的邮件服务 我应该改变什么 当我尝试发送第一封电子邮件 mailgun 官方网站上的说明 时 我收到了相同的错误消息 import Injectable
  • 哪个“if”结构更快 - 语句还是三元运算符?

    有两种类型ifjava 中的语句 经典 if else 和简写 exp value1 value2 一个比另一个快还是它们相同 陈述 int x if expression x 1 else x 2 三元运算符 int x expressi
  • 如何添加后退按钮功能MFSlidemenu?

    我已经在我的项目中实现了 MFSideMenu 它效果很好 但现在我想为每个视图实现后退按钮功能 我尝试这个但不起作用 NSArray array self navigationController viewControllers self
  • Java 详细类加载

    我试图列出 Java 类加载器加载我的类的顺序 如果我使用 verbose参数它将列出它加载的每个接口 类 包括大量接口 例如可序列化 异常等 有没有办法调整此输出 以便它只显示我的主要方法定义的类中加载了哪些类 我想你最好的选择是执行以下
  • Web Worker 在 Chrome 中被主线程阻止

    我有一个网络工作者 https developer mozilla org en US docs Web API Web Workers API basic usage 我希望用它定期发出网络请求 我特别想要的一件事是即使主 JS 执行线程