Javascript 在瀏覽器中調(diào)試

2023-02-17 10:37 更新

在編寫(xiě)更復(fù)雜的代碼前,讓我們先來(lái)聊聊調(diào)試吧。

調(diào)試 是指在一個(gè)腳本中找出并修復(fù)錯(cuò)誤的過(guò)程。所有的現(xiàn)代瀏覽器和大多數(shù)其他環(huán)境都支持調(diào)試工具 —— 開(kāi)發(fā)者工具中的一個(gè)令調(diào)試更加容易的特殊用戶(hù)界面。它也可以讓我們一步步地跟蹤代碼以查看當(dāng)前實(shí)際運(yùn)行情況。

在這里我們將會(huì)使用 Chrome(谷歌瀏覽器),因?yàn)樗鼡碛凶銐蚨嗟墓δ埽渌蟛糠譃g覽器的功能也與之類(lèi)似。

“資源(Sources)”面板

你的 Chrome 版本可能看起來(lái)有一點(diǎn)不同,但是它應(yīng)該還是處于很明顯的位置。

  • 在 Chrome 中打開(kāi) 示例頁(yè)面。
  • 使用快捷鍵 ?F12?(Mac:?Cmd+Opt+I?)打開(kāi)開(kāi)發(fā)者工具。
  • 選擇 ?Sources(資源)? 面板。

如果你是第一次這么做,那你應(yīng)該會(huì)看到下面這個(gè)樣子:


切換按鈕 會(huì)打開(kāi)文件列表的選項(xiàng)卡。

讓我們?cè)陬A(yù)覽樹(shù)中點(diǎn)擊和選擇 hello.js。這里應(yīng)該會(huì)如下圖所示:


資源(Sources)面板包含三個(gè)部分:

  1. 文件導(dǎo)航(File Navigator) 區(qū)域列出了 HTML、JavaScript、CSS 和包括圖片在內(nèi)的其他依附于此頁(yè)面的文件。Chrome 擴(kuò)展程序也會(huì)顯示在這。
  2. 代碼編輯(Code Editor) 區(qū)域展示源碼。
  3. JavaScript 調(diào)試(JavaScript Debugging) 區(qū)域是用于調(diào)試的,我們很快就會(huì)來(lái)探索它。

現(xiàn)在你可以再次點(diǎn)擊切換按鈕 隱藏資源列表來(lái)給代碼騰出一些空間。

控制臺(tái)(Console)

如果我們按下 ?Esc?,下面會(huì)出現(xiàn)一個(gè)控制臺(tái),我們可以輸入一些命令然后按下 ?Enter ?來(lái)執(zhí)行。

語(yǔ)句執(zhí)行完畢之后,其執(zhí)行結(jié)果會(huì)顯示在下面。

例如,1+2 將會(huì)返回 3,而 hello("debugger") 函數(shù)調(diào)用什么也沒(méi)返回,所以結(jié)果是 undefined


斷點(diǎn)(Breakpoints)

我們來(lái)看看 示例頁(yè)面 發(fā)生了什么。在 hello.js 中,點(diǎn)擊第 4 行。是的,就點(diǎn)擊數(shù)字 "4" 上,不是點(diǎn)擊代碼。

恭喜你!你已經(jīng)設(shè)置了一個(gè)斷點(diǎn)?,F(xiàn)在,請(qǐng)?jiān)诘?nbsp;8 行的數(shù)字上也點(diǎn)擊一下。

看起來(lái)應(yīng)該是這樣的(藍(lán)色是你應(yīng)該點(diǎn)擊的地方):


斷點(diǎn) 是調(diào)試器會(huì)自動(dòng)暫停 JavaScript 執(zhí)行的地方。

當(dāng)代碼被暫停時(shí),我們可以檢查當(dāng)前的變量,在控制臺(tái)執(zhí)行命令等等。換句話(huà)說(shuō),我們可以調(diào)試它。

我們總是可以在右側(cè)的面板中找到斷點(diǎn)的列表。當(dāng)我們?cè)跀?shù)個(gè)文件中有許多斷點(diǎn)時(shí),這是非常有用的。它允許我們:

  • 快速跳轉(zhuǎn)至代碼中的斷點(diǎn)(通過(guò)點(diǎn)擊右側(cè)面板中的對(duì)應(yīng)的斷點(diǎn))。
  • 通過(guò)取消選中斷點(diǎn)來(lái)臨時(shí)禁用對(duì)應(yīng)的斷點(diǎn)。
  • 通過(guò)右鍵單擊并選擇移除來(lái)刪除一個(gè)斷點(diǎn)。
  • ……等等。

條件斷點(diǎn)

在行號(hào)上 右鍵單擊 允許你創(chuàng)建一個(gè) 條件 斷點(diǎn)。只有當(dāng)給定的表達(dá)式(你創(chuàng)建條件斷點(diǎn)時(shí)提供的表達(dá)式)為真時(shí)才會(huì)被觸發(fā)。

當(dāng)我們需要在特定的變量值或參數(shù)的情況下暫停程序執(zhí)行時(shí),這種調(diào)試方法就很有用了。

“debugger” 命令

我們也可以使用 debugger 命令來(lái)暫停代碼,像這樣:

function hello(name) {
  let phrase = `Hello, ${name}!`;

  debugger;  // <-- 調(diào)試器會(huì)在這停止

  say(phrase);
}

這樣的命令只有在開(kāi)發(fā)者工具打開(kāi)時(shí)才有效,否則瀏覽器會(huì)忽略它。

暫停并查看

在我們的例子中,hello() 函數(shù)在頁(yè)面加載期間被調(diào)用,因此激活調(diào)試器的最簡(jiǎn)單的方法(在我們已經(jīng)設(shè)置了斷點(diǎn)后)就是 —— 重新加載頁(yè)面。因此讓我們按下 ?F5?(Windows,Linux)或 ?Cmd+R?(Mac)吧。

設(shè)置斷點(diǎn)之后,程序會(huì)在第 4 行暫停執(zhí)行:


請(qǐng)打開(kāi)右側(cè)的信息下拉列表(箭頭指示出的地方)。這里允許你查看當(dāng)前的代碼狀態(tài):

  1. 察看(Watch) —— 顯示任意表達(dá)式的當(dāng)前值。
  2. 你可以點(diǎn)擊加號(hào) + 然后輸入一個(gè)表達(dá)式。調(diào)試器將顯示它的值,并在執(zhí)行過(guò)程中自動(dòng)重新計(jì)算該表達(dá)式。

  3. 調(diào)用棧(Call Stack) —— 顯示嵌套的調(diào)用鏈。
  4. 此時(shí),調(diào)試器正在 hello() 的調(diào)用鏈中,被 index.html 中的一個(gè)腳本調(diào)用(這里沒(méi)有函數(shù),因此顯示 “anonymous”)

    如果你點(diǎn)擊了一個(gè)堆棧項(xiàng),調(diào)試器將跳到對(duì)應(yīng)的代碼處,并且還可以查看其所有變量。

  5. 作用域(Scope) —— 顯示當(dāng)前的變量。
  6. Local 顯示當(dāng)前函數(shù)中的變量,你還可以在源代碼中看到它們的值高亮顯示了出來(lái)。

    Global 顯示全局變量(不在任何函數(shù)中)。

    這里還有一個(gè) this 關(guān)鍵字,目前我們還沒(méi)有學(xué)到它,不過(guò)我們很快就會(huì)學(xué)習(xí)它了。

跟蹤執(zhí)行

現(xiàn)在是 跟蹤 腳本的時(shí)候了。

在右側(cè)面板的頂部是一些關(guān)于跟蹤腳本的按鈕。讓我們來(lái)使用它們吧。

—— “恢復(fù)(Resume)”:繼續(xù)執(zhí)行,快捷鍵 ?F8?。

繼續(xù)執(zhí)行。如果沒(méi)有其他的斷點(diǎn),那么程序就會(huì)繼續(xù)執(zhí)行,并且調(diào)試器不會(huì)再控制程序。

我們點(diǎn)擊它一下之后,我們會(huì)看到這樣的情況:


執(zhí)行恢復(fù)了,執(zhí)行到 say() 函數(shù)中的另外一個(gè)斷點(diǎn)后暫停在了那里??匆幌掠疫叺?“Call stack”。它已經(jīng)增加了一個(gè)調(diào)用信息。我們現(xiàn)在在 say() 里面。

—— “下一步(Step)”:運(yùn)行下一條指令,快捷鍵 ?F9?。

運(yùn)行下一條語(yǔ)句。如果我們現(xiàn)在點(diǎn)擊它,alert 會(huì)被顯示出來(lái)。

一次接一次地點(diǎn)擊此按鈕,整個(gè)腳本的所有語(yǔ)句會(huì)被逐個(gè)執(zhí)行。

—— “跨步(Step over)”:運(yùn)行下一條指令,但 不會(huì)進(jìn)入到一個(gè)函數(shù)中,快捷鍵 ?F10?。

跟上一條命令“下一步(Step)”類(lèi)似,但如果下一條語(yǔ)句是函數(shù)調(diào)用則表現(xiàn)不同。這里的函數(shù)指的是:不是內(nèi)建的如 alert 函數(shù)等,而是我們自己寫(xiě)的函數(shù)。

如果我們對(duì)比一下,“下一步(Step)”命令會(huì)進(jìn)入嵌套函數(shù)調(diào)用并在其第一行暫停執(zhí)行,而“跨步(Step over)”對(duì)我們不可見(jiàn)地執(zhí)行嵌套函數(shù)調(diào)用,跳過(guò)了函數(shù)內(nèi)部。

執(zhí)行會(huì)在該函數(shù)調(diào)用后立即暫停。

如果我們對(duì)該函數(shù)的內(nèi)部執(zhí)行不感興趣,這命令會(huì)很有用。

—— “步入(Step into)”,快捷鍵 ?F11?。

和“下一步(Step)”類(lèi)似,但在異步函數(shù)調(diào)用情況下表現(xiàn)不同。如果你剛剛才開(kāi)始學(xué) JavaScript,那么你可以先忽略此差異,因?yàn)槲覀冞€沒(méi)有用到異步調(diào)用。

至于之后,只需要記住“下一步(Step)”命令會(huì)忽略異步行為,例如 ?setTimeout?(計(jì)劃的函數(shù)調(diào)用),它會(huì)過(guò)一段時(shí)間再執(zhí)行。而“步入(Step into)”會(huì)進(jìn)入到代碼中并等待(如果需要)。詳見(jiàn) DevTools 手冊(cè)。

—— “步出(Step out)”:繼續(xù)執(zhí)行到當(dāng)前函數(shù)的末尾,快捷鍵 ?Shift+F11?。

繼續(xù)執(zhí)行代碼并停止在當(dāng)前函數(shù)的最后一行。當(dāng)我們使用 偶然地進(jìn)入到一個(gè)嵌套調(diào)用,但是我們又對(duì)這個(gè)函數(shù)不感興趣時(shí),我們想要盡可能的繼續(xù)執(zhí)行到最后的時(shí)候是非常方便的。

—— 啟用/禁用所有的斷點(diǎn)。

這個(gè)按鈕不會(huì)影響程序的執(zhí)行。只是一個(gè)批量操作斷點(diǎn)的開(kāi)/關(guān)。

—— 啟用/禁用出現(xiàn)錯(cuò)誤時(shí)自動(dòng)暫停腳本執(zhí)行。

當(dāng)啟動(dòng)此功能,如果開(kāi)發(fā)者工具是打開(kāi)著的時(shí)候,任何腳本執(zhí)行錯(cuò)誤都會(huì)導(dǎo)致該腳本執(zhí)行自動(dòng)暫停。然后我們可以在調(diào)試器中分析變量來(lái)看一下什么出錯(cuò)了。因此如果我們的腳本因?yàn)殄e(cuò)誤掛掉的時(shí)候,我們可以打開(kāi)調(diào)試器,啟用這個(gè)選項(xiàng)然后重載頁(yè)面,查看一下哪里導(dǎo)致它掛掉了和當(dāng)時(shí)的上下文是什么。

Continue to here

在代碼中的某一行上右鍵,在顯示的關(guān)聯(lián)菜單(context menu)中點(diǎn)擊一個(gè)非常有用的名為 “Continue to here” 的選項(xiàng)。

當(dāng)你想要向前移動(dòng)很多步到某一行為止,但是又懶得設(shè)置一個(gè)斷點(diǎn)時(shí)非常的方便。

日志記錄

想要輸出一些東西到控制臺(tái)上?console.log 函數(shù)可以滿(mǎn)足你。

例如:將從 0 到 4 的值輸出到控制臺(tái)上:

// 打開(kāi)控制臺(tái)來(lái)查看
for (let i = 0; i < 5; i++) {
  console.log("value", i);
}

普通用戶(hù)看不到這個(gè)輸出,它是在控制臺(tái)里面的。要想看到它 —— 要么打開(kāi)開(kāi)發(fā)者工具中的 Console(控制臺(tái))選項(xiàng)卡,要么在一個(gè)其他的選項(xiàng)卡中按下 ?Esc?:這會(huì)在下方打開(kāi)一個(gè)控制臺(tái)。

如果我們?cè)诖a中有足夠的日志記錄,那么我們可以從記錄中看到剛剛發(fā)生了什么,而不需要借助調(diào)試器。

總結(jié)

我們可以看到,這里有 3 種方式來(lái)暫停一個(gè)腳本:

  1. 斷點(diǎn)。
  2. ?debugger ?語(yǔ)句。
  3. error(如果開(kāi)發(fā)者工具是打開(kāi)狀態(tài),并且按鈕是開(kāi)啟的狀態(tài))。

當(dāng)腳本執(zhí)行暫停時(shí),我們就可以進(jìn)行調(diào)試:檢查變量,跟蹤代碼來(lái)查看執(zhí)行出錯(cuò)的位置。

開(kāi)發(fā)人員工具中的選項(xiàng)比本文介紹的多得多。完整的手冊(cè)請(qǐng)點(diǎn)擊這個(gè)鏈接查看:https://developers.google.com/web/tools/chrome-devtools。

本章節(jié)的內(nèi)容足夠讓你上手代碼調(diào)試了,但是之后,尤其是你做了大量關(guān)于瀏覽器的東西后,推薦你查看上面那個(gè)鏈接中講的開(kāi)發(fā)者工具更高級(jí)的功能。

對(duì)了,你也可以點(diǎn)擊開(kāi)發(fā)者工具中的其他地方來(lái)看一下會(huì)顯示什么。這可能是你學(xué)習(xí)開(kāi)發(fā)者工具最快的方式了。不要忘了還有右鍵單擊和關(guān)聯(lián)菜單喲。


以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)