了解 Web Worker 中事件处理程序的范围

Understanding scoping of event handlers in web workers

考虑以下 webworker 代码:https://www.html5rocks.com/en/tutorials/workers/basics/

网页:

<button onclick="sayHI()">Say HI</button>
<button onclick="unknownCmd()">Send unknown command</button>
<button onclick="stop()">Stop worker</button>
<output id="result"></output>

<script>
  function sayHI() {
    worker.postMessage({'cmd': 'start', 'msg': 'Hi'});
  }

  function stop() {
    // worker.terminate() from this script would also stop the worker.
    worker.postMessage({'cmd': 'stop', 'msg': 'Bye'});
  }

  function unknownCmd() {
    worker.postMessage({'cmd': 'foobard', 'msg': '???'});
  }

  var worker = new Worker('doWork2.js');

  worker.addEventListener('message', function(e) {
    document.getElementById('result').textContent = e.data;
  }, false);
</script>

然后在 doWork2.js:

self.addEventListener('message', function(e) {
  var data = e.data;
  switch (data.cmd) {
    case 'start':
      self.postMessage('WORKER STARTED: ' + data.msg);
      break;
    case 'stop':
      self.postMessage('WORKER STOPPED: ' + data.msg +
                       '. (buttons will no longer work)');
      self.close(); // Terminates the worker.
      break;
    default:
      self.postMessage('Unknown command: ' + data.msg);
  };
}, false);

因此,当您单击 SayHi 时,doWork2 中定义的 "message" 事件处理程序首先获取该事件。然后它触发另一个 "message" 事件,该事件由打印消息的主页上定义的处理程序拾取。

步骤流程是这样的。

  1. 用户单击按钮,引发消息事件。
  2. 执行doWork2中的handler
  3. doWork2 中的处理程序引发消息事件
  4. 网页上的处理程序被执行

请回答以下 2 个问题:

问题一:上面第2步中为什么触发了doWork2中的handler,而页面上的handler却没有?

问题2:doWork2触发事件后的第4步,为什么页面上的handler执行了,doWork2中的handler却没有递归执行?

doWorks2 事件侦听器之前被触发的原因是因为 javascript 解释您的代码的方式。 Javascript 中的代码执行发生在 2 个方向的异步函数的情况下。有一个调用堆栈,其中包含 运行 按同步顺序或经典顺序排列的命令,然后对于异步函数,有一个消息队列,它按事件添加的顺序对事件进行排队。

查看更多:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

原来在两个不同的对象上有两个postMessage的实现。

问题 1 的答案

调用worker.postMessage()时

...the Worker interface sends a message to the worker's inner scope

因此页面上的消息事件处理程序看不到它。

问题 2 的答案

当调用 self.postMesssage 时,self 是 worker 的全局作用域,其实现如下:

sends back information to the thread that spawned it using the DedicatedWorkerGlobalScope.postMessage method.

因此它不会递归调用自身,因为消息事件仅在生成它的线程中可见。

来源:https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage