Skip to content

Does making maybeRebroadcastQueries async introduce any sort of race condition? I could have sworn I tried this back in the day and ran into issues where the state in the app was incorrect because maybeRebroadcastQueries was no longer synchronous / executed serially. And that added to the fact that the equality function itself was not async so it still took up the 150ms of time (just deferred which allowed flutter to optimize slightly). I may be mistaken. But if that is the case, you could still have it be async and throw it into a queue. #1501

@vincenzopalazzo

Description

@vincenzopalazzo

Does making maybeRebroadcastQueries async introduce any sort of race condition? I could have sworn I tried this back in the day and ran into issues where the state in the app was incorrect because maybeRebroadcastQueries was no longer synchronous / executed serially. And that added to the fact that the equality function itself was not async so it still took up the 150ms of time (just deferred which allowed flutter to optimize slightly). I may be mistaken. But if that is the case, you could still have it be async and throw it into a queue.

Also with the optimized deep equals, a medium sized system (10 observables) amounted to around 30ms per rebroadcast. So about 2 skipped frames.

You could maybe make the equality function, itself, async to maximize benefit and decrease jank.

Maybe something like this:

Example `optimizedDeepEqualsAsync`
// Deep equality check that yields to the event loop between recursive calls
Future<bool> optimizedDeepEqualsAsync(Object? a, Object? b) async {
  // Yield once to avoid blocking
  await Future<void>.delayed(Duration.zero);

  if (identical(a, b)) return true;
  if (a == b) return true;

  if (a is Map) {
    if (b is! Map || a.length != b.length) return false;
    for (var key in a.keys) {
      if (!b.containsKey(key)) return false;
      // Recursive async call
      if (!await optimizedDeepEqualsAsync(a[key], b[key])) return false;
    }
    return true;
  }

  if (a is List) {
    if (b is! List || a.length != b.length) return false;
    for (var i = 0; i < a.length; i++) {
      // Recursive async call
      if (!await optimizedDeepEqualsAsync(a[i], b[i])) return false;
    }
    return true;
  }

  return false;
}

To avoid the jank the developer can pass the async function for equality check, like compute() to move the operation to a different isolate.

Just a quick thought on this. I'd highly recommend using a shared isolate if you go this route. I tried this one with compute, too and found it would increase the equality check time by about 50-100ms (for the spawn cost).

Originally posted by @kvenn in #1496 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority: HighHigh priority to include it inside next releaseneeds more infoMore information is required

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions