-
Notifications
You must be signed in to change notification settings - Fork 65
Description
I’ve been debugging some pretty bad frontend performance in an app using useThreadMessages with streaming enabled. In some cases the UI was dropping to 2 FPS 😭
I know we have a fair amount of re‑rendering going on, but even accounting for that, things felt way slower than expected. So I recorded a performance trace in Chrome and found this:
updateFromUIMessageChunksindeltas.tsis taking a big chunk of the main thread time
- Inside that function, this
assertline seems to be the hotspot :
Lines 80 to 83 in b48f51c
| assert( | |
| messagePart.id === message.id, | |
| `Expecting to only make one UIMessage in a stream, but have ${JSON.stringify(message)} and created ${JSON.stringify(messagePart)}`, | |
| ); |
it is surprising, because this is just an equality check. But my theory is that, regardless of whether the equality check passes, the JSON.stringify calls in the template string are always evaluated eagerly.
Since updateFromUIMessageChunks is called for every delta while streaming, this means we’re doing a full JSON.stringify of the whole message on every new delta.
useThreadMessages({ stream: true })
↓
useStreamingThreadMessages
↓
useStreamingUIMessages
↓
useDeltaStreams (fetches stream deltas)
↓
useEffect in useStreamingUIMessages (on new deltas)
↓
updateFromUIMessageChunksthis happens with both useThreadMessages and useUIMessages
Possible fix
If my understanding is correct, this should be a relatively easy performance win by making the error message lazy, so JSON.stringify only runs on failure.
Happy to provide more details if helpful.