cachapa / firedart

A dart-native implementation of the Firebase Auth and Firestore SDKs
https://pub.dev/packages/firedart
Apache License 2.0
174 stars 62 forks source link

Calling Document.stream causes unnecessary network activity #52

Closed esDotDev closed 9 months ago

esDotDev commented 3 years ago

I've been doing some performance testing, and it seems the lack of local caching is a pretty major issue.

Without it, my app incurs many read calls each time a widget is rebuilt, for example, a StreamBuilder watching a 100 item collection, if the parent of that widget plays a 1s animation, you could incur 6000 read calls right there (60fps, 100 reads each frame). The same interaction with the native sdk shows 0 read calls.

I'm just curious if this is known behavior, or is there a better way to sync your UI to the stream.

Also any chance of local cache being added if this is the cause? Cheers,

cachapa commented 3 years ago

Firedart explicitly has no caching since that adds a whole new layer of complexity to the projects that I'd rather no approach before other aspects that in my mind have higher priority.

I'm not sure I understand your example fully though. A StreamBuilder shouldn't be triggering read calls, unless there's a bug somewhere (either in mine, or in your code).

esDotDev commented 3 years ago

Oh, that would be great if it were a bug and not actually a cache thing, I was just guessing.

So I have something like this:

 StreamBuilder<List<Document>>(
              stream: Firestore.instance.collection("/users/shawn@test.com/books").stream,
              builder: (_, snapshot) {
                if (!snapshot.hasData) return Container();
                return Row(children: snapshot.data.map((e) => Text(" --> ${e.id}.    ")).toList());
              }),

To test whether setState spikes read calls, in init(), I have:

Timer.periodic(Duration(milliseconds: 100), (timer) => setState(() {}))

I have 3 records in this table, It's rebuilding about 600 times a minute, and this is counting as 1800 reads / minute. image

Same code with Native singleton, just counts the initial 3 reads.

If it's worth anything, I'm testing on Windows with firedart, and Android with firebase_core.

esDotDev commented 3 years ago

It seems to spawn a new snapshot listener everytime .stream is called: image

This is all from that one example, running for ~10minutes.

In this shot, you can see the total traffic from the native example, 2 reads image

Am I doing it wrong by binding to the .stream directly?

[EDIT] I tried caching the CollectionRefefence, and doing:

StreamBuilder<List<Document>>(
              stream: booksRef.stream,
              builder:  ...
)

No apparent difference,

cachapa commented 3 years ago

I just checked the code and it seems the stream setup happens every time you call .stream, which is causing those reads. So I guess the issue in on my side :-)

Anyway, my recommendation for now would be for you to find a way to cache the stream object to avoid calling .stream on every rebuild. Thanks for the report!