Почему использование объявления функции не работает для общения с веб-работниками? - PullRequest
2 голосов
/ 23 февраля 2020

TL; DR заключается в том, что когда обработчик onmessage () для веб-работника определяется как объявление функции, а не как выражение функции, он не работает. (По крайней мере, в Chrome.) И я не могу понять, почему.

У меня есть следующий простой пример настройки:

index. html

<!DOCTYPE html>
<html>
<head>
  <title>Web worker test</title>
  <script src="index.js"></script>
</head>
<body>
  <input type="button" value="test1" onclick="run('test1.js')">
  <input type="button" value="test2" onclick="run('test2.js')">
</body>
</html>

index. js

function run(filename) {
  worker = new Worker(filename);
  worker.postMessage("test");
}

test1. js

onmessage = function(msg) {
    console.log(msg.data);
}
console.log(self.onmessage);

test2. js

function onmessage(msg) {
    console.log(msg.data);
}
console.log(self.onmessage);

Вы можете попробовать это самостоятельно на http://mrbean.cryogenia.com/~davedude/webworkertest/. Если вы нажмете кнопку test1, она запишет следующее (по крайней мере Chrome 79.0.3945.117):

ƒ (msg) {
  console.log(msg.data);
}
test1.js:2 test

Это показывает, что функция определена так, как ожидалось, и обработчик работает.

Напротив, когда вы нажимаете test2, все, что вы получаете, это:

ƒ onmessage(msg) {
  console.log(msg.data);
}

Это показывает, что скрипт работает, и функция определена, она просто не работает как обработчик по любой причине.

1 Ответ

1 голос
/ 23 февраля 2020

Свойство onmessage глобального объекта имеет значение setter . Сеттеры не вызываются объявлениями функций; скорее они просто перезаписываются, как если бы delete <fnName> был запущен заранее. Вот еще один пример:

<script>
Object.defineProperty(window, 'fn', {
  set(newVal) {
    console.log('setter invoked');
  },
  configurable: true
});
</script>
<script>
function fn() {
}

console.log(window.fn);
</script>

Как видите, сеттер не вызывается. Состояние свойства fn в window после первого <script> почти такое же, как состояние свойства message в self в веб-работнике в начале сценария веб-работника:

const workerFn = () => {
  console.log(Object.getOwnPropertyDescriptor(self, 'onmessage'));
};
const workerFnStr = `(${workerFn})();`;
const blob = new Blob([workerFnStr], { type: 'text/javascript' });
const worker = new Worker(window.URL.createObjectURL(blob));
<div>Look at results in your browser console, not the snippet console</div>

<br><br>

<img src="https://i.stack.imgur.com/8JND8.png">

Функциональность установки функции в качестве прослушивателя для события message будет действовать только внутри установщика. Но без вызова установщика слушатель не будет присоединен.


Если вам интересно, в спецификации , когда существует объявление функции на верхнем уровне, и это имя уже существует в глобальном объекте, оно не будет воссоздано или инициализировано до самого конца:

Выполнить! varEnvRec.SetMutableBinding(fn, fo, false).

Это выдаст ошибку , только если привязка неизменна (например, если свойство не настраивается). Но onmessage getter / setter настраивается .

...