開發糗事 – 尷尬的 Click
大清早剛上班就遇到了一個極蠢的 BUG,此事必須記錄以作提醒。
我的問題現象很可能很多人都遇到過,但我的問題原因你絕對猜不到。
問題發現
一大早,系統負責人跑過來找我:點擊圖片後彈窗顯示信息的功能怎麼彈出了兩個窗口?也要關兩次纔會關掉?
我:好,我改一下。馬上就好。(心想:嗯?難道 click 事件寫重複了,或者彈窗方法寫重複了?)
開始調試
-
查看 click 事件綁定的相關代碼
因爲這個功能是全局的,所以寫在 common.js 中,並且,由於節點是動態生成的,所以使用 on 事件監聽 click 事件。
/** * 點擊圖片彈窗顯示詳情信息 */ $(".has_small_img").on("click", ".small_img", function() { var src = $(this).attr("src"); layer.open({ type: 2, title: "", closeBtn: 1, shadeClose: true, maxmin: true, area: ["95%", "95%"], skin: "yourclass layer-ext-myskin", content: $.wrapUrl("/Base/ShowMessage?src=" + src), success: function(layero, index) {} }); });
layer 只 open 了一次。
全局搜索了一下 has_small_img 和 small_img 。沒有不合理的地方。
(有點懵…)
那會是哪裏重複調用了呢? -
啓動項目,問題重現
既然 click 事件綁定的部分沒有發現錯誤,那隻好先將項目運行起來,重現一下問題,看一看是否還涉及到別的操作?
前方高能!!!- 點擊圖片。走你~
- 唰…唰…兩個彈窗(咦?還真是兩個…en…換個圖片試試)
- 換個圖片。點…
- 唰…唰…唰(0.0 嗯?什麼鬼?三個?還多一個?)
- 再換一個圖片。click…
- 唰…唰…唰…唰(臥槽,點一次多一個???偷偷擦汗。。。幸虧負責人小姐姐只點了一次,趕緊偷偷改…)
測到這裏,基本可以確定兩個字 嵌套。
但嵌套也分很多種,到底是哪裏嵌套了呢?
對於嵌套綁定,最常用的方法 off 和 unbind 先試一遍(儘管我認爲我的代碼中並沒有嵌套綁定,但現在運行的效果確實是嵌套的效果)。$(".has_small_img") .off("click", ".small_img") .on("click", ".small_img", function() {}); $(".has_small_img") .on("click", ".small_img", function() {}) .off("click", ".small_img"); ...
試了各種解綁方式,結果發現,並沒有什麼卵用。
-
版本還原,追查原因
此時,突然想起一個非常重要的線索,該功能在剛做好提交之後測試時正常的(絕對是正常的,不然我不會提交)。於是,git 的優勢就凸顯出來了。
通過 git,我將代碼還原到最後一次修改該功能的版本,測試,正常。
(總算有點小安慰,至少可以確認該功能的代碼是沒有問題的,不至於像無頭蒼蠅一樣亂撞)
看來,應該是受到其它功能的影響。
繼續追查 git,發現該問題發生在 516 版本(添加了首頁 Gantt 圖加載的功能)之後,而這個版本僅僅新增了這一個功能,雖然這個 Gantt 圖加載的功能看似與 click 事件無絲毫關聯。
將代碼還原爲最新版本,屏蔽了 Ganntt 圖加載的方法,測試,正常。(可以確定,問題就發生在這個看似毫無關係的功能上)。 -
問題確認,大寫的尷尬。
進入 Gantt 圖所在頁面,進一步排查原因。
額,瞬間無語,罪魁禍首居然是:<script src="~/Scripts/common.js" />
一個頁面,引入公用的 js,看似再正常不過的一件事,怎麼會是這個問題的罪魁禍首呢?
-
問題原因
沒錯,理論上,引入公用 js 確實是個正常操作。
但是,這是一個完整的項目,公用 js 早已在佈局頁面中引入過一次,這裏可不就是重複引入了嗎?
而這個頁面又是首頁的局部視圖(PartialView),在首頁加載的時候也進行了加載
每次更換數據時,圖片和其它數據都是異步刷新的,圖片更新了,當然 Gantt 圖頁面也重新加載了,而 Ganntt 圖每重新加載一次,就多綁定一次 click 事件。(因爲之前有說過,這個 click 事件是全局監控的,所以在 common.js 加載時就會運行) -
自己的坑、自己填
尷尬的問題來了,罪魁禍首的一行代碼,恰好是我自己故意加上去的…
我明明知道佈局頁面已經加載過,爲什麼還會加這個呢?
剛纔也有提到,Gantt 頁面是一個 PartialView,顧名思義,就是鑲嵌在主頁面的一個局部視圖,它在運行的時候,使用的是主頁面引入的 js 文件,當然也包括 jquery、common.js 等。
但是,當時在做這個局部視圖的時候,恰好主頁面還沒有完成,無法嵌套進去,所以我是單獨對這個局部視圖測試的,沒有了主頁面的支持,jquery、layer、common.js 等都無法使用,所以,就臨時對這個局部視圖引用了這些 js 文件來做臨時測試,結果提交的時候將這件事忘得一乾二淨。
這要只是引入了一些插件方法之類的,雖然浪費了資源,但好歹不會出現功能性問題,可巧的就是,恰好引進去了一個包含全局監聽事件的 js 。
總結
-
測試代碼及時刪除
即使不能及時刪除,也一定要做好備註,標明時間、原因、以及測試字樣,養成良好的編碼習慣;
-
多用、巧用版本控制軟件
本次問題排查過程中,Git 功不可沒。它幫助我在最短的時間內定位到了問題所在。
一個問題的罪魁禍首,出在另一個幾乎完全不相干的位置,恰好又是一個最容易被遺忘、被忽略的地方。
如果沒有 Git,鬼知道我需要多久才能找到問題原因。