Q20 · Web3 场景优化
你会如何处理"交易发起了,但链上还没确认"的前端体验和性能问题?
⚡ 速记答案(30 秒)
- 使用乐观更新(optimistic UI):本地先把订单状态标记成"提交中"或"待确认",UI 立即反馈
- 监听链上事件 / 轮询交易状态:成功 → 更新状态为"已成交/成功",失败 → 回滚本地状态 + 提示
- 性能上:不要在 UI 主流程里阻塞等待交易确认
- 链上确认逻辑放到后台任务 / 统一管理的 tx manager 中处理
📖 详细讲解
乐观更新模式
用户操作 → 立即更新 UI → 后台发送交易 → 监听结果 → 同步最终状态交易状态机
idle → pending → submitted → confirming → confirmed/failed实现要点
1. UI 响应
• 立即显示"处理中"状态
• 禁用重复提交
• 显示进度指示
2. 后台处理
• 交易队列管理
• 超时处理
• 重试策略
3. 状态同步
• 成功:更新本地状态
• 失败:回滚 + 提示用户
• 超时:提供查询入口
注意事项
• 不要阻塞主线程
• 处理网络中断
• 考虑交易加速/取消
💻 代码示例
交易管理器
type TxStatus = 'pending' | 'submitted' | 'confirmed' | 'failed';
interface Transaction {
id: string;
hash?: string;
status: TxStatus;
data: any;
}
class TransactionManager {
private transactions = new Map<string, Transaction>();
private listeners = new Set<(tx: Transaction) => void>();
// 发起交易 - 乐观更新
async submit(id: string, sendTx: () => Promise<string>) {
// 1. 立即标记为 pending
this.updateTx(id, { status: 'pending', data: {} });
try {
// 2. 发送交易
const hash = await sendTx();
this.updateTx(id, { status: 'submitted', hash });
// 3. 后台等待确认
this.waitForConfirmation(id, hash);
} catch (error) {
// 发送失败 - 回滚
this.updateTx(id, { status: 'failed' });
}
}
private async waitForConfirmation(id: string, hash: string) {
try {
const receipt = await provider.waitForTransaction(hash);
this.updateTx(id, {
status: receipt.status === 1 ? 'confirmed' : 'failed'
});
} catch {
this.updateTx(id, { status: 'failed' });
}
}
private updateTx(id: string, updates: Partial<Transaction>) {
const tx = { ...this.transactions.get(id), ...updates } as Transaction;
this.transactions.set(id, tx);
this.listeners.forEach(fn => fn(tx));
}
}面试技巧:回答性能问题时,先说指标和标准,再讲优化手段,最后结合实际项目经验。