bug 现象描述
Socket.IO 客户端有个奇葩的 bug,详见 Multiple sockets open after reconnect #430。
其实很早就发现这个问题了,客户端监听的事件会多次收到响应,具体表现为:
- 第 1 次断线重连后,收到每条数据都会触发 2 次 callback
- 第 2 次断线重连后,收到每条数据都会触发 3 次 callback
- 第 3 次断线重连后,收到每条数据都会触发 4 次 callback
很明显是个 bug。
之前解决的方式是使用业务方式:即在收到数据后做去重处理,并没有去深究 Socket.IO 的内部原因(当时确实没有心思去研究)。
今天在制作 demo 页面时,此现象引发了我的关注,特地去检查了 Socket.IO 的全部 issues,终于发现了类似 #430 等多个相同故障的 issues,且早在六年前就已经出现这个问题了,因此我更加确定这不是个案。
详细阅读过相关的所有 issues 后,网友们并没有给出很好的解决办法。但是看了广大网友的描述后,心中有了一个思路。
经过排查,确定不是服务端发送数据的问题(即:并不是服务端 emit 了多次相同的数据),而是客户端监听方法(Socket.on()
)被多次触发导致。
这更证实了我先前的思路:on 方法被执行多次,那么给 on 方法传入的 callback 方法被绑定了多次,结果导致多次触发。
这个结论与前面多次断线重连后的现象规律是吻合的!
bug 成因分析
- HTML 页面 loaded,Socket.IO 类库对应的业务代码开始运行
- Socket.IO 类库运行 io 方法连接 WebSocket 服务端(此方法返回 Socket 对象),并开始监听
connect
事件 - 连接成功后,触发
connect
事件,Socket.on
事件监听绑定 callback 完成 - 运行其他业务方法。。。
- 可能网络不稳定、可能是被服务端主动断开、可能是浏览器机制等,长连接断开
- Socket.IO 类库发现连接被断开,尝试重新连接,客户端触发
reconnect
事件 - Socket.IO 类库重连成功,再次触发
connect
事件,导致步骤 3 再次运行。。。(故障源定位成功~)
解决方案
发现了问题根源,剩下的就是 fixed 了~
在业务方法中使用了一个开关变量来记录 Socket 是否已经绑定过事件监听,如果绑定过就跳过,否则才会绑定。
之前的业务方法
|
|
之后的业务方法
|
|
只要避免多次给 Socket 对象绑定 callback,即可解决问题。
注:荆秀网官网 JS 类库已经更新,参见:#L32
done~