Optimistic UI:先更新界面,再等服务器
点赞、收藏、勾选待办这类操作,失败率极低。既然几乎总会成功,就没必要让用户盯着 spinner 等服务器。乐观更新 (Optimistic UI) 的策略是:点击瞬间就把界面更新到成功后的样子,把真正的请求挪到后台;只有在真的失败时才回滚并提示。
乐观策略下,UI 在
就更新了,网络延迟被完全藏在背后;只有命中那次注定失败的请求,才会在响应到达时回滚——这正是它的代价,偶发的「跳一下」。悲观策略永远正确,但每次操作都要付出全额延迟,且按钮在等待期 disabled。两者的取舍由失败的后果决定:点赞错了无伤大雅,用乐观;转账金额,必须悲观。
乐观更新的骨架是先改 UI、失败再回滚:
async function like() {
const prev = snapshot(state);
applyChange(state); // 1. 立即更新 UI
render();
try {
await api.toggleLike(); // 2. 后台发请求
} catch (err) {
restore(state, prev); // 3. 失败回滚
render();
toast('网络错误, 已撤销'); // 4. 失败信号
}
}
警示 · 乐观更新有三个必备零件,缺一不可。其一,操作前快照旧状态 (prev);其二,失败时精确回滚到快照,并处理回滚期间用户又点了的竞态;其三,给用户一个失败信号,通常就是一条
Snackbar。若服务器返回的真实值和乐观猜测不同,例如点赞数被别人同时改了,还要用响应数据校正,而不是简单确认。
它和 Yellow Fade 互补:乐观更新负责让变化来得快,Yellow Fade 负责让变化被看见。许多框架已内建这一模式(React 的 useOptimistic、SWR 与 React Query 的 optimistic mutation),但理解上面三个零件,才知道它们在替开发者做什么。