存在
Share state between users with Realtime Presence.
使用实时在线状态来跟踪多个用户之间的状态。
🌐 Use Realtime Presence to track state between multiple users.
用法 #
🌐 Usage
你可以使用 Supabase 客户端库来跟踪用户之间的在线状态。
🌐 You can use the Supabase client libraries to track Presence state between users.
Presence 是如何运作的 #
🌐 How Presence works
Presence 让每个连接的客户端发布一小部分状态——称为“presence 负载”——到共享通道。Supabase 会将每个客户端的负载存储在一个唯一的 presence 键下,并保持所有连接客户端的合并视图。
🌐 Presence lets each connected client publish a small piece of state—called a “presence payload”—to a shared channel. Supabase stores each client’s payload under a unique presence key and keeps a merged view of all connected clients.
当任何客户端订阅、断开连接或更新他们的状态信息时,Supabase 会触发以下三种事件之一:
🌐 When any client subscribes, disconnects, or updates their presence payload, Supabase triggers one of three events:
sync— 完整状态已更新join— 一个新客户开始跟踪出勤了leave— 客户端已停止追踪在线状态
Presence 并不是为高频更新设计的
Presence 通过服务器同步状态,并在每次更改时通知所有订阅者。快速调用 track()——例如在每次鼠标移动时共享光标位置——会淹没通道并导致性能问题。
🌐 Presence syncs state through the server and notifies all subscribers on every change. Calling track() rapidly — for example on every mouse move to share cursor positions — will flood the channel and cause performance problems.
对于高频率或一次性更新,改用 Broadcast。Presence 最适合用于变化缓慢的状态,比如在线/离线状态、活动文档或当前页面。
🌐 For high-frequency or fire-and-forget updates, use Broadcast instead. Presence is best suited for slow-changing state such as online/offline status, active document, or current page.
同步事件行为
在 sync 事件期间,即使没有用户加入或离开,你也可能同时收到 join 和 leave 事件。这是预期的行为——Presence 会将本地状态与服务器状态进行同步,这个过程可能会触发这些事件。这反映的是状态的同步,而不是真实的用户动作。
🌐 During a sync event, you may receive join and leave events simultaneously, even though no users are joining or leaving. This is expected behavior—Presence reconciles its local state with the server state, which can trigger these events as part of the synchronization process. This reflects state reconciliation, not real user movement.
presenceState() 返回的完整在线状态看起来是这样的:
🌐 The complete presence state returned by presenceState() looks like this:
1{2 "client_key_1": [{ "userId": 1, "typing": false }],3 "client_key_2": [{ "userId": 2, "typing": true }]4}初始化客户端 #
🌐 Initialize the client
从项目的 Connect 对话框 获取项目的 URL 和密钥。
🌐 Get the Project URL and key from the project's Connect dialog.
API 密钥的更改
Supabase 改变了密钥的工作方式,以提升项目安全性和开发者体验。你可以在 GitHub 上阅读完整公告。
🌐 Supabase has changed the way keys work to improve project security and developer experience. You can read the full announcement on GitHub.
它们将在2026年底被弃用,你现在应该改用可发布的(sb_publishable_xxx)和秘密的(sb_secret_xxx)密钥。
在大多数情况下,你可以从项目的 连接 对话框获得密钥,但如果你想要特定的密钥,可以在仪表板的设置 > API 密钥部分找到它们。
🌐 In most cases, you can get keys from the Project's Connect dialog, but if you want a specific key, you can find them in the Settings > API Keys section of the Dashboard.
- 对于新密钥,打开 API 密钥 标签,如果你还没有可发布的密钥,点击 创建新 API 密钥,然后从 可发布密钥 部分复制数值用于客户端操作。对于服务器端操作,则从 密钥 部分复制数值。
- 对于旧版密钥,从 Legacy API Keys 标签中复制
anon密钥用于客户端操作,service_role密钥用于服务器端操作。
1import { createClient } from '@supabase/supabase-js'23const SUPABASE_URL = 'https://<project>.supabase.co'4const SUPABASE_KEY = '<sb_publishable_... key>'56const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)同步并跟踪状态 #
🌐 Sync and track state
监听 sync、join 和 leave 事件,这些事件会在任何客户端加入或离开通道,或更改其状态片段时触发:
🌐 Listen to the sync, join, and leave events triggered whenever any client joins or leaves the channel or changes their slice of state:
1import { createClient } from '@supabase/supabase-js'23const supabase = createClient('your_project_url', 'your_supabase_api_key')45// ---cut---6const roomOne = supabase.channel('room_01')78roomOne9 .on('presence', { event: 'sync' }, () => {10 const newState = roomOne.presenceState()11 console.log('sync', newState)12 })13 .on('presence', { event: 'join' }, ({ key, newPresences }) => {14 console.log('join', key, newPresences)15 })16 .on('presence', { event: 'leave' }, ({ key, leftPresences }) => {17 console.log('leave', key, leftPresences)18 })19 .subscribe()发送状态 #
🌐 Sending state
你可以使用 track() 向所有订阅者发送状态:
🌐 You can send state to all subscribers using track():
1import { createClient } from '@supabase/supabase-js'2const supabase = createClient('your_project_url', 'your_supabase_api_key')34// ---cut---5const roomOne = supabase.channel('room_01')67const userStatus = {8 user: 'user-1',9 online_at: new Date().toISOString(),10}1112roomOne.subscribe(async (status) => {13 if (status !== 'SUBSCRIBED') { return }1415 const presenceTrackStatus = await roomOne.track(userStatus)16 console.log(presenceTrackStatus)17})一个客户端会接收任何订阅了相同主题(在这个例子中是 room_01)的其他客户端的状态。它也会自动触发自身的 sync 和 join 事件处理器。
🌐 A client will receive state from any other client that is subscribed to the same topic (in this case room_01). It will also automatically trigger its own sync and join event handlers.
停止追踪 #
🌐 Stop tracking
你可以使用 untrack() 方法停止追踪出席情况。这将触发 sync 和 leave 事件处理程序。
🌐 You can stop tracking presence using the untrack() method. This will trigger the sync and leave event handlers.
1import { createClient } from '@supabase/supabase-js'23const supabase = createClient('your_project_url', 'your_supabase_api_key')4const roomOne = supabase.channel('room_01')56// ---cut---7const untrackPresence = async () => {8 const presenceUntrackStatus = await roomOne.untrack()9 console.log(presenceUntrackStatus)10}1112untrackPresence()显示选项 #
🌐 Presence options
你可以在初始化 Supabase 客户端时传入配置选项。
🌐 You can pass configuration options while initializing the Supabase Client.
存在键 #
🌐 Presence key
默认情况下,Presence 会在服务器上生成一个唯一的 UUIDv1 密钥来跟踪客户端通道的状态。如果你愿意,可以在创建通道时提供自定义密钥。这个密钥在客户端之间应该是唯一的。
🌐 By default, Presence will generate a unique UUIDv1 key on the server to track a client channel's state. If you prefer, you can provide a custom key when creating the channel. This key should be unique among clients.
1import { createClient } from '@supabase/supabase-js'23const supabase = createClient('SUPABASE_URL', 'SUPABASE_PUBLISHABLE_KEY')45const channelC = supabase.channel('test', {6 config: {7 presence: {8 key: 'userId-123',9 },10 },11})