1. 程式人生 > >專案中遇到的JS閉包問題

專案中遇到的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 總結

要寫好單元測試!!!
要寫好單元測試!!!
要寫好單元測試!!!
重要的事情說三遍。