Когда сообщения приходят быстрее, чем их читают
У живой ленты два ограничения: сообщения нужно показывать достаточно быстро, чтобы не отстать от разговора, и достаточно долго, чтобы их успели прочитать. При большом потоке выполнить оба условия не получится. Тогда поведение ленты зависит от её назначения: показать происходящее сейчас или дать читателю возможность остановиться и разобраться в написанном.
В «Пульсе твиттера» я показывал сообщения из очереди раз в две секунды, чтобы лента не прыгала при каждом поступлении данных. Если в такой очереди накопилось 40 записей, последняя из них появится примерно через 80 секунд. За это время придут новые. Можно ускорить смену карточек, но тогда читать их станет ещё труднее.
У экрана в зале и у ленты, открытой на ноутбуке, разные задачи. В зале хочется видеть, что обсуждают сейчас. Пропустить часть старого потока может быть допустимо. В ленте на ноутбуке читатель может захотеть остановиться на одном сообщении. Если этот текст уедет вверх посреди предложения, высокая скорость доставки ему не поможет.
Для чтения я бы разделил поступление сообщений и обновление видимой части. Новые записи продолжают приходить, но после нажатия на паузу текст перед читателем остаётся на месте. Рядом можно показать кнопку «Есть новые сообщения». Счётчик на ней полезен, если повторная доставка той же записи не увеличивает его ещё раз.
Пауза при этом должна быть доступна отдельной кнопкой. Остановка только по наведению мыши неудобна на сенсорном экране, а при управлении с клавиатуры о ней вообще можно не узнать. Состояние кнопки тоже стоит назвать прямо: «Остановить ленту» и «Продолжить». По неподвижному экрану ещё нельзя понять, включена пауза или пропала связь.
Что происходит за время паузы
Если складывать все входящие сообщения в массив, забытая на ночь вкладка может накопить огромную очередь. Её стоит ограничивать и по числу записей, и по объёму данных. Иначе несколько сообщений с очень длинным текстом займут гораздо больше памяти, чем мы рассчитывали.
Но ограничить массив недостаточно. Нужно выбрать, что будет означать переполнение для читателя. В трансляции мероприятия можно оставить последние сообщения и сообщить, что часть потока пропущена. После паузы кнопка «Перейти к новым» тогда честнее, чем «Продолжить чтение»: продолжить с того же места мы уже не можем.
Если история нужна целиком, её придётся получать отдельно. Текущую ленту можно держать небольшой, а предыдущие записи загружать по запросу. Это уже другая задача, которую нельзя решить, бесконечно увеличивая очередь в браузере. Причём такая история возможна, только если её хранит наш сервис или позволяет получить источник.
Видимые сообщения тоже занимают память. В старом примере я ограничивал их количество, удаляя нижние карточки. Для общего экрана это допустимо. Когда ленту читают в своём браузере, удаление требует осторожности: читатель мог прокрутить вниз и остановиться на одной из этих карточек. Пока он там, этот участок лучше оставить на месте. Перейти к новым сообщениям можно отдельным действием, после которого старую видимую часть уже допустимо заменить.
После разрыва связи
Статус подключения помогает понять, работает ли трансляция: открытая страница сама по себе этого не подтверждает. Но успешное переподключение тоже сообщает лишь о соединении. Из него не следует, что мы получили всё пропущенное.
Если источник поддерживает продолжение с последней полученной записи, можно сохранить её идентификатор и запросить следующие сообщения. Это место приёма данных, а не место чтения: запись могла попасть в очередь, но ещё не появиться на экране. Если источник уже удалил нужный участок истории, восстановить весь пропуск таким способом не получится.
При повторной доставке устойчивый идентификатор записи поможет распознать дубль. Нужно проверять сообщения и в очереди, и в видимой части. Ограниченный набор недавних идентификаторов защищает от повторов только в пределах этого набора. Если источник может повторно прислать более старые записи, потребуется согласовать с ним границу повторной загрузки; бесконечная коллекция всех когда-либо увиденных сообщений снова вернёт нас к проблеме памяти.
Бывает, что продолжить поток нельзя. Тогда после восстановления связи на странице появятся только текущие сообщения. Я бы оставлял в ленте заметную границу с подписью о перерыве. Иначе соседство двух карточек будет создавать впечатление непрерывного разговора, хотя между ними могли пройти десятки сообщений.
Такую ленту полезно проверять с потоком, который заведомо не успеваешь прочитать: поставить на паузу, дождаться переполнения очереди, разорвать соединение и вернуться. После этого на странице должно быть понятно, где чтение можно продолжить, а где часть сообщений пропущена. Для меня это важнее непрерывного движения карточек: у читателя остаётся возможность остановиться и понять, что он видит.