【问题标题】:Why is my Web Worker terminated?为什么我的 Web Worker 被终止了?
【发布时间】:2016-07-22 11:02:54
【问题描述】:

当我遇到一个非常特殊的行为时,我正在尝试处理网络工作者。出于某种原因,它在几秒钟后终止,即使我有代码正在运行。

这是我的代码;

主 JavaScript 文件:

$(document).ready(function () {
    var worker = new Worker("js/TestWorker.js");
    worker.addEventListener('message', function (event) {
        console.log(event.data);
    });

    worker.addEventListener('error', function (event) {
        console.log(event);
    });
});

工人文件:

(function () {
    var updateCounter = 0;

    var updater = function () {
        updateCounter += 1;
        console.log("Update counter: " + updateCounter);

        postMessage("test");
        setTimeout(updater, 10000);
    };

    updater();
})();

如前所述,工作人员会在几秒钟、10-20 秒左右后停止工作。

但如果我将这段代码添加到我的主 JavaScript 文件中;

var check = function () {
    var localWorker = worker;
    // setTimeout(check, 1000);
};

// setTimeout(check, 1000);

工人按预期工作。也不需要 setTimeout 调用,因此它们被注释掉了。 (请注意,我也可以将作业替换为 worker.length 或类似的东西,它仍然可以正常工作。

有人可以解释这种行为吗?工作人员是否被终止并(错误地)被浏览器收集垃圾,或者这里发生了我错过的其他事情?

值得注意的是,我的浏览器 (Chrome) 也没有向控制台输出任何错误或警告。

编辑:无论代码是否在匿名函数内执行,都会观察到相同的行为。

EDIT2:如果我将工作变量放在全局范围内,它不会过早终止。这可能是什么原因?

【问题讨论】:

  • 很好奇。我的印象是 web worker 类似于 DOM 节点,因为它们只能被明确地杀死(即它们不应该简单地超出范围/垃圾收集,特别是因为你已经添加了一些侦听器)。您是否在 FireFox 等中尝试过相同的代码?在我看来,这听起来像是一个错误。
  • @Dave 是的,刚刚在 Firefox 中测试过,可以正常工作。

标签: javascript


【解决方案1】:

一些研究表明,虽然网络工作者应该按照您的预期运行(即不会被明显地垃圾收集),但 Chrome 中存在一些已知问题,这意味着您不能依赖这种行为。

特别感兴趣的是这个非常相似的错误:https://bugs.chromium.org/p/chromium/issues/detail?id=572225,它又引用了一个更潜在的错误:https://bugs.chromium.org/p/chromium/issues/detail?id=572226

这似乎是由于尝试对无法执行任何未来活动的工作人员进行垃圾收集(在这种情况下,垃圾收集将无法检测到,因为它应该是),但检测此状态的逻辑存在缺陷意味着任何与响应传入消息没有直接关系的未决活动都将被忽略。

基本上,虽然您应该能够假设 web-workers 的行为类似于只能显式删除的 DOM 节点,但实际上(目前)您需要确保始终保留对工人可以从某个地方访问,否则当垃圾收集器启动时,它可能会杀死工人。仅当您在工作人员中使用 setTimeout 或类似内容时才需要这样做;如果它只是响应消息,你不会有问题。

【讨论】:

  • 啊,我明白了,有趣!
【解决方案2】:

也许 worker var 必须是全局变量

var worker;  

$(document).ready(function () { 
    worker = new Worker("js/TestWorker.js");     
    worker.addEventListener('message', function (event) {
            console.log(event.data);
    });

    worker.addEventListener('error', function (event) {
        console.log(event);
    }); 
});

【讨论】:

  • 是的,这似乎有些道理。如果我将变量放在全局范围内,工作人员仍然存在。任何想法为什么会这样?
  • 我认为工作变量像任何其他变量一样被垃圾收集,当匿名函数结束时,所有局部变量都被垃圾收集。
  • 嗯,不,我不这么认为。如果是这样的话,我会在更多情况下遇到这个问题,变量消失和失去它们的值等等。
  • 好吧,我错了。我在小提琴中测试它,如果它是一个局部变量,它不会被垃圾收集,它在 Firefox 和 chrome jsfiddle.net/meji/s8umLu1e 中永远运行(没有你的最后一段代码)
【解决方案3】:
(function () {
 ... 
})();

这是一个匿名函数,将在定义后调用一次,然后浏览器将其丢弃。 您的网络工作者被定义为这个范围,这就是为什么它只能在短时间内工作。

【讨论】:

  • 不,不可能。如果代码在全局范围内执行,我会得到相同的行为。
猜你喜欢
  • 2020-11-20
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-20
相关资源
最近更新 更多