# 当有人在您查看未读消息时发帖，聊天会跳过一整块消息

**URL:** <https://meta.discourse.org/t/chat-skips-a-block-of-messages-when-someone-posts-while-youre-catching-up-on-unread-history/416446>\
**Category:** Bug\
**Tags:** chat\
**Created:** [2026 年11 月 3 日 17:21 UTC](https://meta.discourse.org/t/chat-skips-a-block-of-messages-when-someone-posts-while-youre-catching-up-on-unread-history/416446 "2026-11-03T17:21:54Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

作者： ![Luna\_Mora](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/luna_mora/32/527917_2.png) [@Luna\_Mora](https://meta.discourse.org/u/Luna_Mora)\
发布日期： [2026 年11 月 3 日 17:21 UTC](https://meta.discourse.org/t/chat-skips-a-block-of-messages-when-someone-posts-while-youre-catching-up-on-unread-history/416446/1 "2026-11-03T17:21:55Z")

</div>

当一个频道或私信中有未读消息，且其数量超过第一页加载的内容时，如果在您滚动浏览该历史记录时有人发布了新消息，那么已加载页面末尾与新实时消息之间的所有消息都会被跳过。列表会直接从较早的消息跳到新的实时消息（通常相隔数小时），并且没有任何迹象表明有内容缺失。重新加载频道会一次一页地填补这些空缺，因此较大的空缺需要多次重新加载才能补全。

此问题与浏览器或设备类型无关（已在 Firefox 桌面版和安卓版以及 Chrome 安卓版 PWA 上测试）。

复现步骤：

1. 用户 A 和用户 B 共用一个私信或频道。用户 A 阅读到最新消息后离开。
2. 用户 B 发布了 60 条以上的消息。
3. 用户 A 打开私信。页面会在其最后阅读的位置附近加载（下方有约 25 条较新的消息）。
4. 在滚动到该已加载页面的底部之前，用户 B 又发布了一条消息。
5. 用户 A 向下滚动。

预期：在下方加载接下来的 25 条消息页面，以此类推，直到实时消息。

实际：实时消息直接出现在已加载页面之后。滚动到底部时会请求实时消息之后的消息，响应为空，`can_load_more_future` 变为 false，而那 35+ 条中间的消息从未显示。由于实时消息现在可见，`last_read_message_id` 会推进到空缺之后，因此未读指示器也会清除。

以下是我对为何发生此问题的最佳分析：

自 2025 年 12 月左右的一次提交（“FEATURE: respect user presence when chat is on screen”, #36652）以来，`ChatChannel#onNewMessage` 始终通过 `ChatPaneState#handleIncomingMessage` 路由消息，后者在自动滚动时调用 `addMessage`，否则通过 `maintainScrollPosition` 处理。

`ChatMessagesLoader#computeNextTargetMessage` 使用列表中最后一条非暂存（non-staged）消息作为 FUTURE 页面的光标。一旦实时消息位于部分加载列表的末尾，该光标就会跳过所有未加载的历史记录。

此外，`Chat::MessagesQuery.query_paginated_messages` 仅为 FUTURE 页面设置 `can_load_more_future`，仅为 PAST 页面设置 `can_load_more_past`，另一项则为 `nil`。`ChatMessagesLoader#loadMore` 无条件地从 `result.meta` 分配这两项，因此单个 PAST 页面（在打开位于最后阅读位置后稍向上滚动时）会在下方历史记录仍未加载的情况下将 `canLoadMoreFuture` 设置为 `null`。由于 `loadMore` 检查的是 `=== false`，进一步的分页仍然有效。

除此之外，还有一个独立的、更旧的 bug：当 `canLoadMoreFuture` 为 true 时，`#sendNewMessage` 会将消息暂存在列表末尾，而不加载最新页面。一旦消息被确认，它就成为 FUTURE 光标，因此如果您在正在阅读的历史记录中回复较旧的消息，也会发生同样的跳过情况。

我们的社区主要并非以聊天为核心，但我们的用户经常回溯阅读，因此在您未在场的持续对话中遗漏消息是一个问题。我认为这对于以聊天为主的社区来说会是更大的问题，尤其是考虑到现在可以将聊天设置为主页这一新功能。
