乐观 UI,英文叫 Optimistic UI

意思是:

前端先假设这次操作会成功,所以立刻更新界面;后端慢慢处理,成功了就保持,失败了再回滚或提示错误。

比如聊天发送消息。

普通写法是:

1
2
await sendMessageToServer(content)
messages.value.push(userMessage)

效果是:
你点发送后,要等服务器确认成功,消息才出现在界面上。用户会感觉卡。

乐观 UI 写法是:

1
2
3
4
5
6
7
messages.value.push(userMessage)

try {
await sendMessageToServer(content)
} catch {
// 失败了再标记失败,或者删除这条消息
}

效果是:
你一按发送,消息立刻出现在聊天框里。服务器还没确认,但前端先“乐观地相信它会成功”。

你的代码里这里就是乐观 UI:

1
2
messages.value.push({ id: nextMessageId++, role: 'user', content })
messages.value.push({ id: nextMessageId++, role: 'assistant', content: '' })

它没有等 /chat/stream 返回,先把用户消息和 AI 空气泡塞进页面里。

所以你应该立刻看到:

1
2
你:你好
AI:|

这个 | 是你模板里的:

1
<span v-else class="typing-cursor">|</span>

也就是 AI 正在生成的占位符。

乐观 UI 的好处是:。用户感觉软件很灵敏。

坏处是:状态容易打架。比如你这个 Bug:

1
2
3
4
1. 前端乐观地 push 消息
2. watcher 又从后端加载空消息
3. messages 被覆盖成 []
4. 欢迎页又出来了

所以乐观 UI 常常要配合几个东西:

1
status: 'sending' | 'sent' | 'failed'

比如:

1
2
3
4
5
6
messages.value.push({
id: tempId,
role: 'user',
content,
status: 'sending',
})

后端成功后:

1
message.status = 'sent'

失败后:

1
message.status = 'failed'

也就是微信/QQ 那种:

1
2
发送中...
发送失败,点击重试

一句话总结:

乐观 UI 就是:前端先装作成功,把界面更新了;后端如果真的成功就皆大欢喜,失败了再补救。

打个比方:
你去食堂点饭,老板还没做完,小幽已经先帮你把餐盘放桌上了。饭来了就开吃;饭没了,就把餐盘撤掉并告诉你“今日售罄”。这就是乐观 UI。


本站由 楠瓜 使用 Stellar 1.33.1 主题创建。
风起于青萍之末,浪成于微澜之间。