nemequ nemequ - 1 month ago 19
Dart Question

Communicating with a shared worker in Dart

I'm trying to communicate with a shared worker from Dart, but I haven't had any success and I've tried everything I can think of.

As a test, I'm just trying to get a basic worker which simply responds with whatever it is sent working.

Starting from the HTML:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="scaffolded-by" content="https://github.com/google/stagehand">
<title>wtf</title>
<link rel="stylesheet" href="styles.css">
<script defer src="main.dart" type="application/dart"></script>
<script defer src="packages/browser/dart.js"></script>

<!-- <script defer src="test.js"></script> -->
</head>

<body>

<div id="output"></div>

</body>
</html>


JavaScript worker (worker.js):

onconnect = function(e) {
var port = e.ports[0];

port.onmessage = function(e) {
port.postMessage("Worker received message: " + e.data);
}
}


The Dart code (main.dart):

import 'dart:html';
import 'dart:async';

void main() async {
var myWorker = new SharedWorker("worker.js");

myWorker.port.onMessage.listen((msg) {
print("Worker says: " + msg);
});

new Timer.periodic(const Duration(seconds: 1), (timer) {
myWorker.port.postMessage("Hello, world");
});
}


The writer does get invoked every second, and I've verified that the shared worker does run (with chrome://inspect).

To narrow the problem down I threw together a JavaScript version of the Dart code (in test.js) which works as expected. If you comment out the contents of
main()
and uncomment the reference in the HTML to test.js it works. Contents of test.js:

var myWorker = new SharedWorker("worker.js");

myWorker.port.onmessage = function(e) {
console.log("Worker says: " + e.data);
}

setInterval(function() {
myWorker.port.postMessage("Hello, world");
}, 1000);


However, when using the Dart version nothing is written to the console. There are no errors at either compile-time or run-time. It just silently fails.

Any help would be greatly appreciated. I'm probably missing something stupid, but I've been stuck on this for longer than I care to admit…

Answer

Since the worker is a SahredWorker, you should call the method:

myWorker.port.start();

just after attach the onMessage listener, (documentation at MDN):

If the onmessage event is attached using addEventListener, the port is manually started using its start() method


Also, at the listener, the parameter msg is a MessageEvent and the text can be retrieved by accessing data property (same as your JS code):

print("Worker says: " + msg.data);

Follow the whole code with the changes:

import 'dart:html';
import 'dart:async';

void main() async {
  var myWorker = new SharedWorker("worker.js");

  myWorker.port.onMessage.listen((msg) {
        print("Worker says: " + msg.data);
  });
  myWorker.port.start(); 

  new Timer.periodic(const Duration(seconds: 1), (timer) {
        myWorker.port.postMessage("Hello, world");
  });
}

tested with Dart 1.19.1