系统设计
设计一个动态消息应用程序
需求探索
核心功能
(1)浏览包含用户及其朋友帖子的新闻Feed
(2)喜欢和回应Feed帖子
(3)创建和发布帖子
帖子类型
文本和图像
Feed用什么分页
无限滚动
是否会在移动设备上使用
不是优先事项,但良好的移动体验会很好
架构/高级设计

组件职责
服务器:提供HTTP API以获取Feed帖子和创建新的Feed帖子
控制器:控制应用程序内的数据流并向服务发出网络请求
客户端存储:存储整个应用程序所需的数据。在新闻Feed的上下文中,存储的大多数数据将是Feed UI所需的服务器生成的数据
Feed UI:包含Feed帖子列表和用于撰写新帖子的UI
(1)Feed帖子:呈现Feed帖子的数据,并包含用于与帖子交互的按钮(喜欢/回应/分享)
(2)帖子撰写器:WYSIWYG(所见即所得)编辑器,供用户创建新的Feed帖子
渲染方法
传统的Web应用程序在何处呈现内容方面有多种选择,无论是在服务器端还是客户端呈现
服务器端渲染(SSR):在服务器端渲染HTML,这是最传统的方式。最适合需要SEO且不需要大量用户交互的静态内容。博客、文档站点、电子商务网站等网站都是使用SSR构建的。
客户端渲染(CSR):在浏览器中呈现,通过使用JavaScript将DOM元素动态添加到页面中。最适合交互式内容。仪表盘、聊天应用程序等应用程序是使用CSR构建的。
新闻 feed 应用程序介于两者之间,既有大量静态内容,又需要交互。 实际上,Facebook 使用了一种混合方法,它提供了两全其美的效果:使用 SSR 快速初始加载,然后对页面进行水合以附加用于用户交互的事件侦听器。 后续内容(例如,当用户到达 feed 末尾时添加的更多帖子)和页面导航将使用 CSR。
数据模型
新闻 feed 显示从服务器获取的帖子列表,因此此应用程序中涉及的大部分数据将是服务器生成的数据。 唯一需要的客户端数据是帖子撰写器中输入字段的表单状态。
| 实体 | 来源 | 属于 | 字段 |
|---|---|---|---|
| Feed | 服务器 | Feed UI | posts (Post 列表), pagination (分页元数据) |
| Post | 服务器 | Feed 帖子 | id, created_time, content, author (一个 User), reactions, image_url (对于包含图像的帖子) |
| User | 服务器 | 客户端存储 | id, name, profile_photo_url |
| NewPost | 用户输入 (客户端) | 帖子撰写器 UI | message, image |
尽管 Post 和 Feed 实体分别属于 feed 帖子和 feed UI,但所有服务器生成的数据都可以存储在客户端存储中,并由需要它们的组件查询。
客户端存储的形状在这里并不特别重要,只要它采用可以从组件轻松检索的格式即可。 从第二页获取的新帖子应与之前的帖子合并到一个列表中,并更新分页参数 (cursor)。
Feed列表优化
Feed列表指的是包含Feed帖子项目的容器元素
无限滚动
当用户滚动到当前已加载feed的末尾时,无限滚动feed会通过获取下一组帖子来工作。这会导致用户看到一个加载指示器和一个短暂的延迟,用户必须等待获取和显示新帖子。
虚拟列表
Feed帖子优化
乐观更新
乐观更新是一种性能技术,客户端在用户交互后立即反映更新后的状态,该交互会命中服务器,并乐观地假设服务器请求成功,对于大多数请求都应该如此。这使用户可以获得即时反馈并提高感知性能。如果服务器请求失败,我们可以恢复 UI 更改并显示错误消息。
对于新闻 feed,乐观更新可以通过立即显示用户的反应和更新的反应总数来应用于反应交互。
乐观更新是现代查询库(如 Relay、SWR 和 React Query)内置的一个强大功能。