16個你可能不知道的JavaScript調試技巧
對于調試JavaScript,當然是越快越好,我們在這里列舉了一些如何更加快速高效調試JS的重要竅門。
更加快速地調試JavaScript
熟悉了解工具對于完成任務來說有著重要的作用。盡管JavaScrip是t出了名的難調試,但如果你知道一些竅門,那你可以花更少的時間去解決這些error和bug。
我們在這里列舉了16個你可能不知道的調試技巧,但它們可能是你想要在下次調試JavaScript代碼之前記住的。
如果你想更快地調試JavaScript的bug,你可以嘗試Raygun崩潰報告( Raygun Crash Reporting ),它可以提供給你關于bugs的告警以及堆棧追蹤(stack trace)。
雖然許多技巧也同樣適用于其他的檢查器(inspector),但這里提及的大部分的技巧是基于Chrome和Firefox的。
1. debugger
除了console.log,debugger是我最喜歡的快速直接的調試工具。如果你在代碼中嵌入debugger;,Chrome執(zhí)行到這里時會自動停止。你甚至可以把它放在條件語句中,這樣它只有在你需要的時候才會運行。
- if (thisThing) {
- debugger;
- }
- if (thisThing) {
- debugger;
- }
2. 在表格中顯示對象
有時候你想看一組特別復雜的對象。你可以用console.log來打印出整個列表,也可以使用console.table來幫助顯示。這樣可以使你更簡單明了地看到你所處理的對象。
- var animals = [
- { animal: 'Horse', name: 'Henry', age: 43 },
- { animal: 'Dog', name: 'Fred', age: 13 },
- { animal: 'Cat', name: 'Frodo', age: 18 }
- ];
- console.table(animals);
它將會輸出:
3. 嘗試所有的尺寸
盡管在你的桌上擁有每一種移動設備特別棒,但這并不現實。不如重新調整視覺視口(viewport)的大小?Chrome提供了你所需要的一切。打開瀏覽器的inspector并點擊選中設備模式(device mode)的按鈕。你就可以觀察到媒體查詢(media queries)了。
4. 如何快速找到你需要的DOM元素
在元素面板中標記一個DOM元素,并在控制臺中使用它。Chrome的Inspector會保存歷史記錄中最近的5個元素,最后被標記的元素會被顯示成 1,以此類推。如果你按順序標記“item4“,”item-3“,”item-2“,”item-1“,”item-0“,那么你可以像下圖這樣在控制臺中訪問DOM節(jié)點。
5. 用console.time()和console.timeEnd()來衡量loops快慢
知道一段代碼到底需要多長時間來執(zhí)行是很有幫助的,尤其是當你在調試執(zhí)行速度慢的代碼的時候。你甚至可以通過給函數賦上不同的標簽值來設置多個timer。讓我們看看它是怎么工作的:
- console.time('Timer1');
- var items = [];
- for (var i = 0; i < 100000; i++) {
- items.push({index: i});
- }
- console.timeEnd('Timer1');
它將會輸出:
6. 得到函數的堆棧追蹤
你可能知道JavaScript框架可以快速產生很多代碼。
你會有許多的視圖,并且觸發(fā)很多事件,所以你終究會遇到一個情況,會想知道是什么觸發(fā)了一個特定的函數調用。因為JavaScript不是一個非常具有結構性的語言,所以有時候你很難知道發(fā)生了什么事,什么時候發(fā)生了這件事。這就是使用console.trace(或者直接在控制臺中使用trace)的時候了。試想一下你想查看在第33行car實例中關于funcZ的函數調用的整個堆棧追蹤:
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
第33行會輸出:
現在我們可以發(fā)現func1調用了func2,func2調用了func4,而func4創(chuàng)建了一個Car的實例并調用了car.FuncX,以此類推。盡管你認為自己已經對腳本特別熟悉,你仍然會發(fā)現這個方法特別得方便。如果你想提高你的代碼質量,你可以獲取所有的追蹤和相關的函數。它們中的每個都是可點擊的,你可以來回切換,對你來說就像一個菜單一樣。
7. 解壓縮代碼使得調試JavaScript更加簡單
有時候你可能會在線上的產品中遇到這樣的問題,服務器并不能提供源代碼映射(souce maps)的功能。不用怕,Chrome可以將你的JavaScript文件解壓縮成更加易讀的形式。這些代碼不會和真的代碼一樣有幫助,但是至少你能明白發(fā)生了什么。你可以點擊在inspector中源代碼視圖下方的 {}
按鈕來格式化代碼。
8. 快速找到需要被調試的函數
如果你想要在一個函數中設置一個斷點,有兩種方法:
- 在inspector中找到那行,添加一個斷點
- 在腳本代碼中添加debugger
上述的兩種方法,你都需要自己手動在文件中找出你需要調試的特定的那一行代碼。一個比較不為人知的辦法是,在控制臺中使用debug(函數名),這樣腳本會在執(zhí)行到這個函數時自動停下。
這個方法特別快,但缺點是它沒法使用在私有函數和匿名函數上。除此之外,這大概是最快找到需要調試函數的方法了。(注意:有一個函數叫做console.debug,盡管名字相似,但和這個并不是一回事)
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
在控制臺中輸入debug(car.funcY),腳本會在有函數調用car.funcY時停下并進入調試模式。
9. 排除與bug無關的腳本
如今我們在web應用中會用到許多的庫和框架,它們中的大部分是經過完整的測試并且相對而言可以被假設成是沒有bug的。但是debugger還是會步入所有這些與調試任務沒有關系的文件。解決的方法是把你不需要調試的腳本放進黑盒里,這里頭也可以包括一些你自己寫的腳本代碼。你可以在這篇調試黑盒的 文章 中閱讀到更多的細節(jié)。
https://raygun.com/blog/javascript-debugging-with-black-box/
10. 在復雜的調試中找到重要的事情
在更多復雜的調試情境中,我們有時會想要輸出許多行。在這里,我們可以利用各種console函數來使輸出使輸出的內容保持一個更易讀的結構。比如,console.log,console.debug,console.warn,console.info,console.error等等。你可以在inspector中篩選它們。有時候這可能不是你在調試時想要達到的效果,但如果需要,你可以使你輸出的信息更加多樣性并有自己的風格。當你想調試JavaScript時,你可以使用CSS來創(chuàng)建你自己的格式化控制臺信息:
- console.todo = function(msg) {
- console.log(‘ % c % s % s % s‘, ‘color: yellow; background - color: black;’, ‘–‘, msg, ‘–‘);
- }
- console.important = function(msg) {
- console.log(‘ % c % s % s % s’, ‘color: brown; font - weight: bold; text - decoration: underline;’, ‘–‘, msg, ‘–‘);
- }
- console.todo(“This is something that’ s need to be fixed”);
- console.important(‘This is an important message’);
它將會輸出:
在console.log()中,你可以使用%s來代表string,%i來代表integers,%c來代表自定義風格。你可能可以找到其他更好的方法來使用這些風格。如果你使用單頁應用框架(single page framework),你或許想要message對應一種風格,model對應一種風格,collections對應一種風格,而controller對應另一種風格,等等。
11. 查看特定的函數調用和參數
在Chrome的控制臺中,你可以查看一些特定的函數。每次這些函數被調用時,傳入函數的參數就會被輸出。
- var func1 = function(x, y, z) {
- //....
- };
它會輸出:
這是一個查看傳入函數參數的好辦法。最理想的情況下,控制臺可以辨別出函數需要多少個參數,但實際上并不能。在上述的例子中,func1需要三個參數,但只傳入了兩個。如果在代碼中沒有做好處理,這樣會導致潛在的bug。
12. 快速在控制臺中訪問元素
一個在控制臺中更快地完成選擇器查詢(querySelector)的方法是使用. ('css-selector')會返回第一個匹配,.$$('css-selector')會返回所有的匹配。如果你使用一個元素多于一次,那么可以把它存為一個變量。
13. Postman是非常好的工具
許多開發(fā)者使用Postman去配合Ajax請求的使用。Postman特別得棒,但令人煩惱的是,每打開一個新的瀏覽器窗口,就需要寫一個新的請求對象,然后再測試它。
有時候用瀏覽器更加簡單。當你這么做時,如果是一個密碼安全頁面(password-secure page),你不再需要為認證cookie擔心。
在Firefox編輯和重新發(fā)送請求,你只需要打開Insepctor,到Network標簽頁下,右鍵點擊你想要修改的請求然后編輯,再重新發(fā)送。
現在你可以更改任何你想要的東西,更改header,編輯參數,然后點擊重新發(fā)送。
下面我展示了一個有著兩種不同屬性的請求:
14. 在節(jié)點上設置斷點
DOM可以是一件特別有趣的事情。有時候有些東西改變了,你卻不知道為什么。然而,當你需要調試JavaScript時,你可以通過Chrome使一個DOM元素停止改變。你甚至可以看見它的屬性。在Chrome的Inspector中,右鍵點擊那個元素并選擇一個設置斷點的條件:
15. 使用頁面提速服務(page speed service)
有許多服務和工具可以幫助你審查頁面的JavaScript,找出那些運行緩慢和有問題的地方。其中的一個工具是 Raygun Real User Monitoring 。除了幫助找到JavaScript問題(如外部腳本加載緩慢,不必要的CSS,過大的圖片),這個工具還在其他方面也十分有幫助。它還可以幫你找到一些無意間導致加載時間過長,或者腳本無法正常執(zhí)行的JavaScript問題。
你還可以用它來測量JavaScript代碼的性能提高,并跟蹤變化。
16. 多使用斷點
最后,合理正確地使用斷點可以幫助你成功調試。嘗試在不同的場景下用不同的方式使用斷點。
你可以點擊元素來設置斷點,從而那個元素被修改時執(zhí)行會停止。你也可以在開發(fā)者工具的Debugger或者Sources標簽頁(取決于你的瀏覽器)中,為任何源代碼設置XHR斷點來停止Ajax請求。在同樣的地方,當異常拋出時代碼的執(zhí)行也會被暫停。你可以在瀏覽器中使用各種斷點來最大化你找到bug的幾率,而不是把時間花在尋找外部的工具上。
總結
綜上所述,有許多方法可以幫助調試JavaScript代碼。我們在這兒已經列舉了其中的16個。如果你想開始找一些依靠瀏覽器之外的工具幫助優(yōu)化瀏覽器,這兒還有一篇特別有幫助的 文章 列舉了一些JavaScript的調試工具。無論怎樣,你應該能夠利用這些調試技巧開始調試你的JavaScript代碼了,使你的代碼沒有bug,并為部署和發(fā)布做好準備!