0Pricing
Frontend Academy · 课时

实时界面模式

应用乐观更新以提供即时反馈,离线时使用本地队列,并比较传入数据,仅更新界面中发生变化的项目。

实时界面模式 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

实时意味着真实的交互体验

实时体验不仅意味着速度快,还意味着响应及时、行为可预测,并且能够包容延迟。三种核心模式是:乐观更新、本地排队和智能差异比较。

乐观更新

在服务器确认之前,用户执行操作后立即更新界面。如果服务器拒绝该操作,则回滚更新。这会让应用感觉即时响应。

async function likePost(id) {
  // 1. Optimistically update UI:
  setLikes(l => ({ ...l, [id]: (l[id] || 0) + 1 }));
  setLiked(prev => ({ ...prev, [id]: true }));

  try {
    await fetch(`/api/posts/${id}/like`, { method: 'POST' });
  } catch (err) {
    // 2. Rollback on failure:
    setLikes(l => ({ ...l, [id]: (l[id] || 1) - 1 }));
    setLiked(prev => ({ ...prev, [id]: false }));
    toast.error('Could not like — please retry');
  }
}

使用临时 ID 的乐观更新

对于新创建的项目,请先在本地为其分配临时 ID。响应到达后,再将其替换为服务器生成的真实 ID。

async function addComment(text) {
  const tempId = `tmp-${Date.now()}`;
  setComments(c => [...c, { id: tempId, text, pending: true }]);

  try {
    const saved = await fetch('/api/comments', {
      method: 'POST',
      body: JSON.stringify({ text })
    }).then(r => r.json());

    setComments(c => c.map(m => m.id === tempId ? saved : m));
  } catch (err) {
    setComments(c => c.map(m => m.id === tempId ? { ...m, error: true } : m));
  }
}

离线时进行本地排队

网络中断时,请将操作放入本地队列,网络恢复后再重放。这样用户可以继续工作。

const queue = JSON.parse(localStorage.getItem('queue') || '[]');

function enqueue(action) {
  queue.push(action);
  localStorage.setItem('queue', JSON.stringify(queue));
  trySend();
}

async function trySend() {
  while (queue.length && navigator.onLine) {
    const action = queue[0];
    try {
      await fetch(action.url, action);
      queue.shift();
      localStorage.setItem('queue', JSON.stringify(queue));
    } catch {
      break; // stop until online
    }
  }
}

window.addEventListener('online', trySend);

比较传入的实时数据

如果服务器推送整个列表,请将其与当前状态进行差异比较,只更新发生变化的部分,从而避免不必要的重新渲染和动画闪烁。

function applyServerSnapshot(newList, currentList) {
  const current = new Map(currentList.map(i => [i.id, i]));
  const result = newList.map(item => {
    const prev = current.get(item.id);
    if (!prev) return { ...item, _state: 'new' };
    if (prev.updatedAt !== item.updatedAt) return { ...item, _state: 'updated' };
    return prev;
  });
  return result;
}

基于补丁的更新

这比完整快照更好:服务器只发送发生变化的字段。请逐步应用这些变化,这样可以减少带宽使用并加快渲染速度。

// Server sends: { type: 'patch', id: 42, fields: { likes: 11 } }
ws.on('message', (msg) => {
  if (msg.type === 'patch') {
    setPosts(posts => posts.map(p =>
      p.id === msg.id ? { ...p, ...msg.fields } : p
    ));
  }
});

限制高频更新

某些数据流每秒会发送大量更新(鼠标位置、股票行情)。请将界面更新限制在约 60Hz,以避免浏览器卡顿。

import { throttle } from 'lodash-es';

const applyUpdate = throttle((data) => {
  setData(data);
}, 16); // ~60fps

ws.on('tick', applyUpdate);

在线状态指示器

实时显示其他在线或正在输入的用户。服务器发布在线状态事件,客户端使用头像渲染列表。

ws.on('presence', ({ users }) => {
  setOnlineUsers(users);
});

ws.on('typing', ({ user, isTyping }) => {
  setTypingUsers(t => isTyping
    ? [...t.filter(u => u.id !== user.id), user]
    : t.filter(u => u.id !== user.id));
});

连接状态横幅

离线或正在重新连接时,显示一个不显眼的横幅。完全重新连接后将其隐藏。当用户能够看到当前发生的情况时,他们对延迟的容忍度会高得多。

{!isConnected && (
  <div className="connection-banner">
    Reconnecting... Your changes will sync when you're back online.
  </div>
)}

冲突解决

实时应用必须处理并发编辑之间的冲突。策略包括:最后写入获胜(简单但可能丢失数据)、版本向量、OT(操作转换)和 CRDT(Yjs、Automerge)。

用于协作的 CRDT

CRDT(无冲突复制数据类型)支持在没有中央服务器的情况下进行实时协作编辑。相关库包括:Yjs、Automerge。Figma、Linear 和 Notion 风格的应用都在使用它们。

性能:虚拟化列表

实时信息流可能会变得很长。请使用虚拟化列表(react-virtuoso、@tanstack/react-virtual),只渲染可见项目——无论总数量多少,内存和 CPU 使用量都能保持稳定。

快速检查

实时界面中的“乐观更新”是什么?

回顾:实时界面模式

乐观更新让应用感觉即时响应,失败时则回滚。为新创建的项目使用临时 ID。使用本地排队确保离线时也能持久保存操作。对服务器更新进行差异比较或应用补丁,以避免重新渲染。限制高频数据流的更新频率。显示在线、正在输入等在线状态以及连接横幅。使用 CRDT(Yjs、Automerge)进行协作编辑。对较长的实时列表进行虚拟化。

常见问题解答

「实时界面模式」课时是免费的吗?

是的 — 「实时界面模式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。

「实时界面模式」这节课中我会学到什么?

应用乐观更新以提供即时反馈,离线时使用本地队列,并比较传入数据,仅更新界面中发生变化的项目。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Frontend Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「实时界面模式」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Frontend Academy 课中编写并运行代码吗?

能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. WebSocket API:打开、消息、关闭与错误
  2. Socket.io 客户端集成
  3. 用于单向流式传输的服务器发送事件
  4. 实时界面模式
← 返回 Frontend Academy