d-markey / squadron

Multithreading and worker thread pool for Dart / Flutter, to offload CPU-bound and heavy I/O tasks to Isolate or Web Worker threads.
https://pub.dev/packages/squadron
MIT License
85 stars 0 forks source link

error when using `JsonSerializable` on web #15

Closed Run10Break1 closed 1 year ago

Run10Break1 commented 1 year ago

recently, I stuck with a problem on the web. below is an error.

error: ["$W","TypeError: Instance of 'minified:z<dynamic>': type 'minified:z<dynamic>' is not a subtype of type 'List<double>'","TypeError: Instance of 'minified:z<dynamic>': type 'minified:z<dynamic>' is not a subtype of type 'List<double>'\n    at Object.b (http://localhost:62206/workers/neverland_worker.dart.js:282:3)\n    at Object.i4 (http://localhost:62206/work...

I figure out that the error comes from type casting on .g.dart, it changes from weak type (important, JS doesn't have a generic type) to strict type like List<double>.

size: const SizeConverter().fromJson(json['size'] as List<double>),

so, when you have an object containing other objects and want to encode the object on the Worker class and decode it on the Service class using code generated by JsonSerializable, change the type to dynamic.

below is an example.

class SizeConverter implements JsonConverter<Size, List<double>> {

  const SizeConverter();

  @override
  Size fromJson(List<double> json) {
    return Size(json[0], json[1]);
  }

  @override
  List<double> toJson(Size object) {
    return [object.width, object.height];
  }
}

on the Web, there isn't a type like List<double>, only List; so change like this.

class SizeConverter implements JsonConverter<Size, dynamic> {

  const SizeConverter();

  @override
  Size fromJson(dynamic json) {
    return Size(json[0], json[1]);
  }

  @override
  dynamic toJson(Size object) {
    return [object.width, object.height];
  }
}

I know that README also says you should take care when using JsonSerializable, but I want to show another case.

d-markey commented 1 year ago

Hello,

Thanks for your feedback. That's right, types such as Map<K,V>/List<T> loose their specialization when crossing worker boundaries on Web platforms.

Using dynamic is one way to go. I believe you could also use a bare List. Using List<whatever> is doomed because whatever will not come through from the caller to the worker!

Also, have you tried using https://pub.dev/packages/squadron_builder? It should help you get rid of some boilerplate code as well as handle type considerations. The code generator tries its best to minimize side effects related to the lack of generics when communicating with a Web Worker. Note that I've never tested it with JsonConverter. So do not hesitate to file an issue if you have problems squadron_builder :-)

Closing this issue for now.

Run10Break1 commented 1 year ago

thank you, I will try squadron_builder

ps, I really appreciate you for making Squadron : )