練習 - 使用 Visual Studio Code 進行偵錯
是時候開始實踐剛學習到的偵錯工具知識了。 看來我們正好有個完美機會。 我們正在自家的 Tailwind Traders 應用程式中開發新功能,其中可以多種貨幣來顯示產品的價格。 某位同事為此功能撰寫了一些程式碼,卻苦於找不出程式碼哪裡發生問題。 讓我們來協助他。
在 Visual Studio 工作區中建立 JavaScript 檔案
在此練習中,您需要使用 JavaScript 檔案來練習偵錯。 若要使用偵錯工具啟動控制項,JavaScript 檔案必須位於 Visual Studio 工作區中。
應用程式的目標是設定三種貨幣、美元、歐元和日元之間的匯率。 然後,我們要以其他貨幣顯示 10 EUR
的價值,並取得小數點後兩位數的結果。 程式需針對每種新增的貨幣,計算其他所有貨幣的匯率。
在 Visual Studio Code 中,於
./nodejs-debug/
子資料夾內建立名為mycurrency.js
的檔案。將下列程式碼貼入新的檔案編輯器中:
const rates = {}; function setExchangeRate(rate, sourceCurrency, targetCurrency) { if (rates[sourceCurrency] === undefined) { rates[sourceCurrency] = {}; } if (rates[targetCurrency] === undefined) { rates[targetCurrency] = {}; } rates[sourceCurrency][targetCurrency] = rate; rates[targetCurrency][sourceCurrency] = 1 / rate; } function convertToCurrency(value, sourceCurrency, targetCurrency) { const exchangeRate = rates[sourceCurrency][targetCurrency]; return exchangeRate && value * exchangeRate; } function formatValueForDisplay(value) { return value.toFixed(2); } function printForeignValues(value, sourceCurrency) { console.info(`The value of ${value} ${sourceCurrency} is:`); for (const targetCurrency in rates) { if (targetCurrency !== sourceCurrency) { const convertedValue = convertToCurrency(value, sourceCurrency, targetCurrency); const displayValue = formatValueForDisplay(convertedValue); console.info(`- ${convertedValue} ${targetCurrency}`); } } } setExchangeRate(0.88, 'USD', 'EUR'); setExchangeRate(107.4, 'USD', 'JPY'); printForeignValues(10, 'EUR');
若要儲存檔案,請按下 Ctrl+S (Windows、Linux) 或 Cmd+S (Mac)。
建立啟動設定
我們將大量使用偵錯工具,因此需要為應用程式建立啟動設定。
在 Visual Studio Code 的 [ 執行 ] 索引標籤上,選取 [建立 launch.json 檔案 ],然後選取 Node.js 調試程式。
Visual Studio Code 會在工作區根中建立
.vscode/launch.json
組態檔,並開啟啟動檔案進行編輯。根據預設,系統會建立啟動設定來執行目前已開啟的檔案。 在此範例中,此開啟檔案為
mycurrency.js
。 您可以修改啟動組態,自訂程式在您進行偵錯時應該如何啟動。在啟動組態中,檢視
program
屬性的值。{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launch Program", "skipFiles": [ "<node_internals>/**" ], "program": "${workspaceFolder}/nodejs-debug/mycurrency.js" } ] }
${workspaceFolder}
表示工作區的根。
關閉
.vscode/launch.json
檔案。
注意
您可以選取右下角的 [新增組態],為專案建立不同的啟動組態。
分析問題
請確定您的 Visual Studio Code 環境已準備好監視偵錯流程:
- 偵錯工具面板應該會於左側開啟。 使用左側的 [執行] 索引標籤圖示來切換面板的可見度。
- 偵錯主控台應該會在底部開啟。 您可以選取 [檢視]>[偵錯主控台],或按下 Ctrl+Shift+Y++ (Windows、Linux) 或 Cmd+Shift+Y++ (Mac) 來開啟主控台。
您現在已可準備開始偵錯。
在偵錯工具啟動控制項中,啟動已啟用偵錯功能的程式 (綠色箭號)。
程式應該很快便會完成。 這是正常的,因為您尚未新增任何中斷點。
您應該會在偵錯主控台中看到這段文字,以及例外狀況。
The value of 10 EUR is:
11.363636363636365
- 11.363636363636365 USD
/app/node-101/currency.js:23
return value.toFixed(2);
^
TypeError: Cannot read property 'toFixed' of undefined
at formatValueForDisplay (/app/node-101/currency.js:23:16)
at printForeignValues (/app/node-101/currency.js:32:28)
at Object.<anonymous> (/app/node-101/currency.js:40:1)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
at Module.load (internal/modules/cjs/loader.js:815:32)
at Function.Module._load (internal/modules/cjs/loader.js:727:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
at internal/main/run_main_module.js:17:11
此程式的目標是設定三種貨幣 (USD、EUR、JPY) 之間的匯率,並以所有其他貨幣顯示 10 EUR
的價值,並取得小數點後兩位數的結果。
我們可在這裡看見兩個錯誤 (Bug):
- 小數點後的位數超過兩位。
- 程式發生例外狀況而損毀,無法顯示
JPY
值。
提示
- 將
"outputCapture": "std",
設定至啟動組態檔,以增加記錄輸出。 - 設定 [記錄點],而不是中斷點,以避免停止程式執行。 記錄點不會「中斷」到偵錯工具,而是將訊息記錄到主控台。 在偵錯無法暫停或停止的生產伺服器時,記錄點特別適合插入記錄。
修正數字顯示
我們會從第一個錯誤開始修正。 由於此程式碼不是您所撰寫,且程式碼中呼叫了各種函式,因此我們要先使用逐步執行來了解執行流程。
使用中斷點和逐步執行
若要新增斷點,請在 上的第 39printForeignValues(10, 'EUR');
行左邊界中選取 。
再次開始偵錯,並使用 [逐步執行] 偵錯控制項逐步執行 printForeignValues()
函式:
檢查變數狀態
現在花點時間檢查 [變數] 面板上各個變數值。
value
和sourceCurrency
變數的值為何?- 針對
rates
變數,您是否看到三個預期的機碼,USD
、EUR
和JPY
?
使用 [逐程序] 偵錯控制項逐步進行,直到變數 convertedValue
設定完成為止:
使用 [逐程序] 控制項五次之後,您應該會看到 convertedValue
變數的值被設定為如預期的 11.363636363636365
。
如果我們再執行一次逐程序,就會看到 displayValue
變數的值。 此值應該是格式化字串,以兩位數 11.36
顯示。
然後,我們可得出程式到目前為止,convertToCurrency()
與 formatValueForDisplay()
函式看似正確,並傳回預期的結果。
更正錯誤
使用 [逐步執行] 控制項一次,來觸及對 console.info()
函式的呼叫。 仔細查看此程式碼。 您有在這裡看到錯誤嗎?
我們需要使用 displayValue
變數來修正此程式錯誤,而非 convertedValue
變數來列印值。
更新您的
currency.js
檔案,以使用正確的變數名稱。 將對第 32 行console.info()
函式的呼叫變更為使用displayValue
變數,而非convertedValue
變數:console.info(`- ${displayValue} ${targetCurrency}`);
將變更儲存至檔案。
重新啟動程式。
檢查程式是否正確將 USD
值顯示為 11.36
。 第一個錯誤:已解決。
找出損毀的原因
現在讓我們來了解程式為何損毀。
在您的
currency.js
檔案中,移除您在第 39 行上設定的中斷點。在 [中斷點] 窗格中勾選 [Uncaught Exceptions] 方塊,以強制程式在引發例外狀況之後暫停。
再次在偵錯工具中執行程式。
程式應會在例外狀況發生時暫停,並在編輯器視窗中間顯示大型錯誤報告。
查看執行停止的那一行,並注意例外狀況訊息 TypeError: Cannot read property 'toFixed' of undefined
。 根據該訊息,即可推斷 value
參數函式具有 undefined
值,而非數字。 此錯誤是造成例外狀況的原因。
倒轉呼叫堆疊
您在錯誤訊息下方看到的「堆疊追蹤」,可能有點不易理解。 好消息是,Visual Studio Code 可為您處理函式呼叫堆疊。 根據預設,其只會在 [呼叫堆疊] 窗格中顯示有意義的資訊。 讓我們使用呼叫堆疊資訊來尋找導致此例外狀況的程式碼。
我們知道例外狀況是在呼叫 formatValueForDisplay()
函式時擲回。
前往偵錯工具面板的 [呼叫堆疊] 窗格。
若要查看呼叫
formatValueForDisplay()
函式的位置,請按兩下其底下的函式,也就是printForeignValues
函式。Visual Studio Code 前往
currency.js
檔案中的printForeignValues
函式,其中呼叫了formatValueForDisplay()
函式:const displayValue = formatValueForDisplay(convertedValue);
仔細檢查此程式碼。 引發例外狀況的參數是來自 convertedValue
變數。 您必須找出讓此參數值變成 undefined
的時間點。
其中一個選項是在此行新增中斷點,並在每次停在這一行的中斷點時檢查變數。 但是,我們不知道何時可能出現錯誤的值,且在複雜的程式中,這種偵錯方法可能會很麻煩。 讓我們看看替代方法。
新增條件中斷點
在我們的案例中,只有在 convertedValue
變數的值為 undefined
時,才能讓偵錯工具於此中斷點停止。 幸好 Visual Studio Code 可以使用滑鼠右鍵選項來執行此動作。
在您的
currency.js
檔案中,於第 31 行的左邊界按一下滑鼠右鍵,並選取 [新增條件式中斷點]。以滑鼠右鍵按一下之後,請輸入下列條件來觸發中斷點,然後按下 [Enter]:
`convertedValue === undefined`
重新啟動程式。
程式現在應該會在第 31 行停止,我們可以檢查呼叫堆疊值。
觀察目前的狀態
讓我們花一些時間分析目前的程式狀態。
convertedValue
變數的值來自對convertToCurrency(value, sourceCurrency, targetCurrency)
函式的呼叫。 我們需要檢查此函式呼叫中的參數值,並確認其正確無誤。我們尤其須檢查
value
變數,並確認它具有預期的值10
。
看一下 convertToCurrency()
函式的程式碼。
function convertToCurrency(value, sourceCurrency, targetCurrency) {
const exchangeRate = rates[sourceCurrency][targetCurrency];
return exchangeRate && value * exchangeRate;
}
您會知道此程式碼的結果是 undefined
。 您也知道變數 value
已設定為 10
。 此資訊會有助我們瞭解問題必定出在 exchangeRate
變數的值。
在您的 currency.js
檔案中,將滑鼠指標暫留在 rates
變數上方以加以查看:
您嘗試取得從 EUR
到 JPY
的匯率,但若展開 EUR
值,則只會看到 USD
的轉換率。 JPY
的轉換率遺失了。
修正消失的轉換率
現在您知道有些轉換率遺失了,讓我們來了解原因。 若要移除所有現有中斷點,請選取 [中斷點] 窗格中的 [移除所有中斷點] 圖示。
監看匯率變數
讓我們設定中斷點來監看 rates
變數。
在您的
currency.js
檔案中,於setExchangeRate(0.88, 'USD', 'EUR');
函式的第37
行新增中斷點。在 [監看式] 窗格中,選取 [加號],然後輸入
rates
。每次變更
rates
變數的值時,更新的值會顯示在 [監看式] 窗格中。重新啟動程式。
當中斷點在第一次呼叫
setExchangeRate()
函式停止時,請使用 [逐程序] 控制項。在 [監看式] 窗格中,查看
rates
變數的值。此時,如我們所預期,
USD
與EUR
有符合的相對轉換率。再次在對
setExchangeRate()
函式的第二次呼叫中執行逐程序。您會看到
USD
與JPY
有符合的相對轉換率,但EUR
與JPY
之間卻沒有。
是時候查看 setExchangeRate()
函式的程式碼了。
function setExchangeRate(rate, sourceCurrency, targetCurrency) {
if (rates[sourceCurrency] === undefined) {
rates[sourceCurrency] = {};
}
if (rates[targetCurrency] === undefined) {
rates[targetCurrency] = {};
}
rates[sourceCurrency][targetCurrency] = rate;
rates[targetCurrency][sourceCurrency] = 1 / rate;
}
此函式的關鍵在於最後那兩行。 看來您找到第二個錯誤了! 轉換率只會設定於 sourceCurrency
和 targetCurrency
變數之間。 此程式也需要計算已新增之其他貨幣的轉換率。
修正程式碼
讓我們針對轉換率問題修正程式碼。
更新您的
currency.js
檔案,以計算其他貨幣的轉換率。將第 12 行和第 13 行的程式碼:
rates[sourceCurrency][targetCurrency] = rate; rates[targetCurrency][sourceCurrency] = 1 / rate;
改為此更新的程式碼:
for (const currency in rates) { if (currency !== targetCurrency) { // Use a pivot rate for currencies that don't have the direct conversion rate const pivotRate = currency === sourceCurrency ? 1 : rates[currency][sourceCurrency]; rates[currency][targetCurrency] = rate * pivotRate; rates[targetCurrency][currency] = 1 / (rate * pivotRate); } }
將變更儲存至檔案。
更新的程式碼會為 sourceCurrency
和 targetCurrency
以外的任何貨幣設定轉換率。 程式會使用 sourceCurrency
的轉換率來推斷其他貨幣與 targetCurrency
之間的轉換率。 程式碼接下來會據此設定其他貨幣的轉換率。
注意
此修正只有在 sourceCurrency
和其他貨幣間的匯率已經存在時才有效,但在這個案例中是可接受的限制。
測試修正
讓我們來測試變更。
移除所有中斷點和監看變數。
重新啟動程式。
您現在應該能在主控台中看到預期的結果,且沒有任何損毀。
The value of 10 EUR is:
- 11.36 USD
- 1220.45 JPY
這樣就大功告成了。 您已修正此程式碼。 您現在可以使用 Visual Studio Code 對事前不知道的程式碼進行有效地偵錯了。 做得好!
清除開發容器
完成專案之後,您可能想要清除開發環境,或使其回到一般狀態。
刪除 GitHub Codespaces 環境,可確保您可將您為帳戶取得的每個核心免費時數權利數量最大化。
重要
如需 GitHub 帳戶權利的詳細資訊,請參閱 GitHub Codespaces 每月包含的儲存體和核心時數。
登入 GitHub Codespaces 儀表板 (https://github.com/codespaces)。
找出您目前從 GitHub 存放庫來源的
MicrosoftDocs/node-essentials
Codespaces。開啟 Codespace 的操作功能表,然後選取 [刪除]。