项目中遇到的JS闭包问题

0x00 发现问题

今天在写聊天室的过程中,遇到一个匪夷所思的问题,当时真是一脸懵逼,检查了好几遍都没问题,而且奇怪的是,只要刷新一下就恢复正常。搞得我差点设置在切换后自动刷新了。当然,这样用户体验很不好,所以静下心来找答案。

问题:当切换房间后,无法添加聊天记录

切换房间有两种方式:
1. 先跳转到房间选择页面,再选择一个房间
2. 直接跳转到一个房间
这种问题看起来就像是切了房间就不能发送消息了,而且两个都出了问题,真是头大。。。

0x01 试错过程

1. 客户端到底有没有发送出数据

首先,看看server端输出调试信息,确定发送没问题。

客户连接,断开连接,加入房间都输出了调试消息。

已经在某房间:71ee20ff-06ea-fda0-bca6-b91ad91264a8

上面这条日志就是切换房间,(输出很简陋(“▔□▔)/),71ee20ff-06ea-fda0-bca6-b91ad91264a8是房间ID,用Guid模块生成的。

{ type: 1, content: ‘asdasd’ } ‘ef4d090a-e022-9d18-4df9-c2364ca7cf30’

上面这条日志就是切换房间后发送消息,切换到ID为ef4d090a-e022-9d18-4df9-c2364ca7cf30的房间了。

2. 确定发生问题的模块

Server端看来是暂时没什么问题,看看客户端。
客户端我用了Vue配合Vue-router来开发的,能省了我不少事。
我是以功能来划分模块和页面的,其实说起来就3个:注册登陆、选择房间、进入聊天室。
前面两个模块出问题的几率比较小。所以我重新梳理了一遍最后一个模块。

                socket.on('chat message', function (data) {

                        /*{
                         msg:{
                         type:1,
                         content:"123"
                         },
                         userInfo:{
                         id:123,
                         nickName:"123",
                         headimgurl:"123123"
                         }
                         }*/

                        self.addMessage(data);


                    });

核心代码其实很简单哈,就是监听Server端的chat message消息,然后将消息数据交给addMessage函数处理,实现添加消息记录,自动滚动到底部等等。
我先在addMessage函数中log一下,发现,居然是正常的,我内部维护的一个msgList数组确实是有增加,但是为什么不显示在界面上呢?!,真是纳闷。

3. 寻找问题所在

难道是Vue-router的Bug?难道是Vue的Bug?仔细想想觉得可能性不大,于是测试了一下。自己模拟聊天数据。
在模块载入的ready钩子中,我用MockJS帮我生成随机的聊天数据,插入msgList

   var msglist = Mock.mock({
            'list|3-6': [{
                msg: {
                    type: 1,
                    content: '@sentence(1,2)'
                },
                userInfo: {
                    id: 123,
                    nickName: "@cname",
                    headimgurl: "123123"
                }
            }]
        });
        console.log();

        this.msgList = msglist.list;

测试发现一点问题也没有,显示正常。
于是,我想,那我在chat message事件响应的时候将聊天数据追加在数组尾部呢?
结果,我发现,原来此msgList 和彼msgList 不是同一个变量!我切换房间后,发送了两条消息,然后我收到了两条,插入msgList 后,发现输出的msgList的长度就是2,没有包括MockJS帮我生成的数据。
我突然想到,应该是闭包搞的鬼
最后,经过一点点的调试。最后发现,当切到其他房间时,socket没有重新绑定新的房间,在socket监听事件中,引用着之前的房间的实例,导致垃圾回收机制不能回收变量。所以会出现两个msgList变量。。。。

0x03 总结

要写好单元测试!!!
要写好单元测试!!!
要写好单元测试!!!
重要的事情说三遍。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue项目闭包的应用非常广泛,以下是一些真实的例子: 1. 在Vue组件,常常使用闭包来创建私有状态和方法,以保护组件内部数据不被外部访问或修改。例如,在一个计数器组件,使用闭包来保存计数器的值。 ``` <template> <div>{{count}}</div> </template> <script> export default { data() { const self = this return { getCount: (function() { let count = 0 return function() { return count } })(), increment: (function() { let count = 0 return function() { count++ self.$emit('update:count', count) } })() } } } </script> ``` 2. 在Vue指令,常常使用闭包来创建私有状态和方法,以存储指令绑定的数据和方法。例如,在一个自定义滚动指令,使用闭包来保存滚动条的位置和滚动事件处理函数。 ``` Vue.directive('my-scroll', { bind(el, binding) { const self = this const state = (function() { let scrollTop = 0 return { getScrollTop() { return scrollTop }, setScrollTop(newTop) { scrollTop = newTop el.scrollTop = scrollTop }, onScroll(e) { scrollTop = e.target.scrollTop binding.value(scrollTop) } } })() el.addEventListener('scroll', state.onScroll) } }) ``` 3. 在Vue插件,常常使用闭包来创建私有变量和方法,以避免与其他插件或全局作用域发生命名冲突。例如,在一个全局通知插件,使用闭包来保存通知队列和通知显示函数。 ``` const notify = (function() { let queue = [] let isShowing = false const showNext = function() { if (queue.length > 0) { const message = queue.shift() isShowing = true // 显示通知逻辑 } else { isShowing = false } } return function(message) { queue.push(message) if (!isShowing) { showNext() } } })() Vue.prototype.$notify = notify ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值