Replies: 2 comments 4 replies
-
I'd start by reviewing the docs page on performance, particularly the section on high-frequency actions, if you haven't seen it already. You are right to be cautious about sending high-frequency updates to the store. I've not used any of these myself, but I think there are a few ways to handle this.
private Enum CancelID { case highFrequencySubscription }
//
return .run { send in
// setting up high-volume subscription
for await value in self.fooClient.highFrequencyAsyncStream() {
await send(.receivedFoo(value))
}
}
.throttle(id: .highFrequencySubscription, for: .seconds(1), scheduler: self.mainQueue, latest: false) Alternatively, I think you could handle this at the concurrency level with Apple's import AsyncAlgorithms
//
return .run { send in
for await value in self.fooClient.highFrequencyAsyncStream().throttle(for: /* ??? */, clock: /* ??? */, latest: false) {
await send(.receivedFoo(value))
}
} If your high-frequency dependency is already a publisher instead of an AsyncStream, you could just use it and any Combine operators directly: return .publisher {
self.fooClient.highFrequencyPublisher()
.throttle(/* ... */)
// and any other Combine operators you want
} The nice thing about doing it this way, in the reducer, is the dependency can remain totally agnostic how frequently its caller is able to take updates. |
Beta Was this translation helpful? Give feedback.
-
One option would be to create an Effect with three endpoints. One receives and accumulates updates for batch processing, the second triggers processing the batch and a third returns an AsyncSequence that will iterate with the results of each batch. All of these can can be async, as to not block the main thread. A timer can be used to call the processing endpoint at the desired interval, which will return another set of updated results via the AsyncSequence when processing the batch is complete. That could trigger updates to the UI. Alternatively, if it's a high-frequency issue, not just a load issue, the Effect itself could connect to the web-socket, and receive / submit high-frequency responses directly, without the need to run them though the reducer. Rather, only the processing trigger and results AsyncSequence would send actions to handle the results. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello,
We have some features that pull their data via http and then subscribe to "real-time" updates via a websocket. In certain circumstances, the updates cause ui lag (particularly when scrolling) and we have a rather complicated system of batching updates and applying them all at once at 1-second intervals or whenever scrolling ceases, whichever is later. I'm wondering whether it might be possible to attack this from the other side, allowing changes to flow into the store as they arrive but preventing them from triggering SwiftUI updates until scrolling is complete. It seems like it might be simpler to implement this way, but I don't know if a mechanism like that exists. I almost want a "shadow store" which operates on a copy of the state and then overwrites the real state all at once. Any ideas welcome!
Beta Was this translation helpful? Give feedback.
All reactions