web.MessageChannel is the equivalent to isolate ports, but on web. It'd be nice if we could make a library like isolate_channel.dart called message_channel.dart or something, with utilities for making a stream channel over a MessageChannel.
I managed to do it with:
import 'dart:async';
import 'dart:js_interop';
import 'package:stream_channel/stream_channel.dart';
import 'package:web/web.dart' as web;
/// Returns a [StreamChannel] that communicates over [port].
///
/// The channel will dartify incoming messages and jsify outgoing messages.
StreamChannel<Object?> messagePortChannel(web.MessagePort port) {
final input = StreamController<Object?>();
final output = StreamController<Object?>();
port.onmessage = (web.MessageEvent event) {
input.sink.add(event.data.dartify());
}.toJS;
// This happens if message can't be deserialized on this side of the port
// usually a browser bug, or something like SharedBuffers or other corner
// cases; not likely to happen in our code.
port.onmessageerror = (web.MessageEvent event) {
// Close any transferred port (just in case)
for (final p in event.ports.toDart) {
p.close();
}
// Include origin in error message, if there is one.
final originStr = event.origin.isNotEmpty
? ' (Origin: ${event.origin})'
: '';
input.sink.addError(
FormatException(
'MessagePort dropped a message due to '
'deserialization failure$originStr',
),
);
}.toJS;
port.start();
output.stream.listen(
(m) {
port.postMessage(m.jsify());
},
onDone: () {
unawaited(input.sink.close());
port.close();
},
);
return StreamChannel(input.stream, output.sink);
}
But it's not perfect, among other things when using it with package:json_rpc_2, RpcException can't be sent over it, I think because int becomes num/double. I stopped exploring.
Instead I ended up JSON encoding all the messages. And I honestly don't know which is most efficient anyways.
web.MessageChannel is the equivalent to isolate ports, but on web. It'd be nice if we could make a library like
isolate_channel.dartcalledmessage_channel.dartor something, with utilities for making a stream channel over aMessageChannel.I managed to do it with:
But it's not perfect, among other things when using it with
package:json_rpc_2,RpcExceptioncan't be sent over it, I think because int becomes num/double. I stopped exploring.Instead I ended up JSON encoding all the messages. And I honestly don't know which is most efficient anyways.