Hallo Rolf,
ich nutze ein bereites Spektrum and Web-Techniken und ja, ich verwende postMessage und innerhalb der WebWorker auch async Methoden. Ich bin mir nun aber relativ sicher, dass es ein Bug im Firefox sein muss. Nachfolgend ein Beispielcode, der den Sachverhalt reproduziert.
Könntest du eventuell mal testen, ob auch bei dir im Firefox der WebWorker an beliebiger Stelle auf einmal aufhört, die noch offenen Task abzuarbeiten? In der Console man nachvollziehen, wieviele Tasks abgearbeitet wurden. Chrome/Chromium läuft sauber durch und arbeitet alle ab. Firefox bricht an eine beliebigen Stelle ab.
Hier der Code:
Datei: index.html
<html>
<head>
<title>Web Worker test</title>
</head>
<body>
<button role="button" id="start">Start</button>
<div id="result"></div>
</body>
<script type="module" src="./index.js"></script>
</html>
Datei: index.js
const runWorker = () => {
let workerURL = new URL('./worker.js', import.meta.url);
let worker = new Worker(workerURL, { type: "module" });
worker.onmessage = ({ data: { cmd, result } }) => {
if (cmd == 'mainWorkerFinished') {
worker.terminate();
document.getElementById('result').innerHTML = JSON.stringify(result, null, null);
} else {
document.getElementById('result').innerHTML = 'unknown message';
}
};
worker.onerror = (error) => {
console.log('main worker error: ' + error.toString());
};
worker.postMessage({
cmd: 'runMainWorker'
});
}
document.getElementById('start').addEventListener('click', () => {
document.getElementById('result').innerHTML = 'running ...';
runWorker();
});
Datei: worker.js
let fileTask = {}
const performTasks = () => {
let waitingTask = Object.entries(fileTask).find(([fileID, entry]) => entry.status == 'waiting');
if (waitingTask) {
let subWorkerURL = self.location.href;
let subWorker = new Worker(subWorkerURL, { type: "module" });
subWorker.onmessage = ({ data: { cmd, fileID } }) => {
switch (cmd) {
case 'subWorkerFinished': {
subWorker.terminate();
fileTask[fileID].status = 'finished';
console.log('finished ' + fileID);
performTasks();
break;
};
default: {
console.log('unknown command')
}
}
};
subWorker.onerror = (error) => {
console.log(error);
};
subWorker.postMessage({
cmd: "runSubWorker", fileID: waitingTask[0]
});
} else {
// no more waiting tasks
self.postMessage({
cmd: "mainWorkerFinished", result: fileTask
})
}
}
const runMainWorker = () => {
// build large number of tasks
let tasks = 70;
while (tasks) {
fileTask['fileID_' + tasks] = {
status: "waiting"
}
tasks--;
}
performTasks();
}
const runSubWorker = async (fileID) => {
// simulate async task and wait for 2 seconds
await new Promise(r => setTimeout(r, 500));
self.postMessage({
cmd: "subWorkerFinished", fileID
});
}
self.onmessage = ({ data: { cmd, fileID } }) => {
switch (cmd) {
case 'runMainWorker': {
runMainWorker();
break;
}
case 'runSubWorker': {
runSubWorker(fileID);
break;
}
default: {
console.log('unknown command');
self.terminate();
}
}
}