如何处理Socket.io场景下双用户同时操作产生的交互冲突问题
双端实时同步操作冲突处理方案
核心冲突判定规则
- 优先级划分:页面跳转类操作优先级高于滚动类操作。页面跳转属于全局状态切换,滚动属于单页面内的局部操作,只要任意一端触发跳转事件,直接终止当前进行中的滚动同步流程,优先执行跳转同步。
- 同类型操作判定:相同类型的操作(同时滚动/同时跳转)统一采用最后操作生效原则,所有上报的操作事件均携带毫秒级时间戳,时间戳更新的操作优先生效,旧操作直接丢弃。
具体场景处理
同时滚动场景
- 本地滚动事件做节流处理,每50~100ms上报一次即可,不需要回调每触发一次就发,降低高频事件带来的冲突概率。
- 滚动事件上报字段需要包含:时间戳、当前页面标识、外层垂直RecyclerView滚动偏移量、当前激活的内层水平RecyclerView索引、内层RecyclerView滚动偏移量。
- 收到对端滚动事件后,先做两层判定:首先判断当前本地页面是否和事件携带的页面一致,不一致直接丢弃;其次判断事件时间戳是否晚于本地最后一次生效的操作时间戳,符合要求才执行同步滚动,否则直接丢弃。
- 执行对端同步滚动操作时,临时屏蔽本地的滚动监听回调,滚动完成后100~200ms再恢复监听,避免同步滚动触发的本地回调又上报到对端,形成循环同步。
同时跳转页面场景
- 跳转事件上报字段需要包含:时间戳、目标页面标识、跳转携带参数(如分类ID、返回层级)。
- 收到对端跳转事件后,直接比对事件时间戳和本地最后一次操作的时间戳,若对端时间更新,直接覆盖本地当前操作,执行对应跳转;若本地操作时间更新,直接丢弃对端事件。
- 跳转完成后两端主动上报一次当前的页面状态做校准,避免事件丢失导致两端状态不一致。
参考事件结构
// 滚动同步事件结构 data class SyncScrollEvent( val timestamp: Long, val pageName: String, val outerScrollOffset: Int, val activeInnerRvPosition: Int, val innerScrollOffset: Int ) // 页面跳转同步事件结构 data class SyncNavigateEvent( val timestamp: Long, val targetPage: String, val params: Map<String, Any>? = null )
内容的提问来源于stack exchange,提问作者Stack Overflow
相关产品推荐
相关产品推荐

