TGViewer
C# Short Posts 🔞 C# Short Posts 🔞 @dimasshortposts · 306 subscribers
Post #435 465
🌊 На гребне волны. Стриминг вместо ToList. Часть 1: Server-Sent Events

Мы потихоньку улучшаем базу знаний и переводим в неё всё больше пользователей — и я начал задумываться, где и как её можно оптимизировать. Давно облизывался на стриминг: мне самому не западло написать ToListAsync там, где надо отдать кучу объектов, часто это норм. Но интересно же, как можно иначе.

Тут как раз попалась статья про IAsyncEnumerable, я и призадумался. Только мне в таких статьях вечно не хватает одного: рассказывают, как это ОТДАВАТЬ с бэка, и молчат, как это ПРИНИМАТЬ на фронте — насколько удобно, что вообще существует. А цепляет меня именно вторая половина. Так что сел и разобрал по-человечески, с обеих сторон. Начну с самого «из коробки» способа — Server-Sent Events.

💡 Для бэка идея простая: вместо «собрал всё и отдал одним JSON» открываешь одно долгоживущее соединение, по которому сервер капает события по мере готовности. Физически это обычный GET, на который сервер отвечает с Content-Type text/event-stream и просто не закрывает ответ — пишет в него «data: ...» по кусочку, а соединение висит открытым. Браузер видит каждый кусок сразу.

На бэке в .NET 10 это буквально одна строчка — TypedResults.ServerSentEvents, которому скармливаешь IAsyncEnumerable. Он сам сериализует каждый объект в data: и делает SSE-обёртку (дикпикосик 1).

За что можно полюбить SSE — это фронтендная часть. Не нужна вообще никакая библиотека: в браузере есть встроенный EventSource. Открыл, повесил обработчик, внутри JSON.parse(e.data) — всё (дикпикосик 2).

У событий есть имена, так что можно слать разнотипные: event: article на каждую статью, event: done в конце. И EventSource сам переподключится, если соединение оборвётся. Это, на минуточку, ровно та механика, на которой стримит ответы ChatGPT.

🔞 НО Пара важных «НО»:

🟢 axios сюда не умеет — он про обычные запрос-ответ, потокового чтения событий у него нет. Нужен либо нативный EventSource (для GET), либо @microsoft/fetch-event-source, если надо POST или кастомные заголовки. Сам EventSource умеет только голый GET без заголовков — авторизацию вешаешь на куку или токен в query.

🟢 не забываем CancellationToken на бэке. Соединение живёт долго, и если клиент отвалился, а ты токен не прокинул, сервер продолжит тянуть строки из БД в никуда и держать коннект. В минимал-апи токен прилетает в хендлер сам (это RequestAborted) — просто пробрось его через [EnumeratorCancellation].

🟢 авто-реконнект — палка о двух концах: когда стрим закончился, надо явно сказать клиенту «всё» (я шлю событие done и закрываю EventSource), иначе он радостно переподключится и начнёт качать заново.

🟢 SSE — это текст и только GET, плюс на HTTP/1 лимит соединений на домен. Для «сервер пушит данные клиенту» — отлично, для двунаправленного — это уже вебсокеты.

📝 По памяти: раз отдаём через IAsyncEnumerable по строке — весь список в куче разом не лежит, footprint ≈ одна строка. Каждую строку мы всё равно материализуем в объект и сериализуем, так что это не «zero-copy», но в памяти будет всего один объект, а не все пачки.

Дальше возьму NDJSON — более ручной и чуть экзотичный способ, где на фронте уже придётся повозиться руками.

#aspnet #dotnet #performance
  • ❤ 6
  • 🙏 2
More from @dimasshortposts
  1. Sep 26, 2026🧵 Тредик для вопросов по докладу про MAF на дотнексте В докладе многие подробности опусти…
  2. Sep 23, 2026Даже самым хардкорным ребятам надо отдыхать, так что отдыхаем, мои чюваки 🕺 🧑‍💻dp🥁 #he…
  3. Sep 16, 2026🎯 Instrumented Tier0: профилирование кода В прошлый раз мы разобрали два уровня компиляци…
  4. Sep 15, 2026🔜 Готовлюсь к DOTNEXT 2026 В прошлом году за две недели до выступления я зачитывал свой д…
  5. Sep 9, 2026C# Short Posts 🔞 pinned «🐸 О чём этот канал? Кажется, я уже достаточно давно веду этот к…
  6. Sep 9, 2026🐸 О чём этот канал? Кажется, я уже достаточно давно веду этот канальчик, и пора бы описат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →