ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(有些夢想,縱使永遠也沒辦法實現,縱使光是連說出來都很奢侈。但如果沒有說出來溫暖自己一下,就無法獲得前進的動力。——九把刀)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
什麼是debug
- 名字的由來
一位名叫葛麗絲·霍波(Grace Hopper)的美國海軍准將及計算機科學家,同時也是世界最早的一批程序設計師之一。有一天,她在調試設備時出現故障,拆開繼電器後,發現有隻飛蛾被夾扁在觸點中間,從而“卡”住了機器的運行。於是,霍波詼諧的把程序故障統稱爲“臭蟲(BUG)”,把排除程序故障叫DEBUG
- debug的本質
Debug是一種程序,一種調試工具,說白了就是供程序員檢查修改問題的工具
爲什麼需要debug
- 調試是定位軟件瑕疵的最直接和最有效的方法 。沒有哪個程序員能一下子寫出沒有錯誤的代碼.而使用以調試器爲主的調試工具進行調試是定位瑕疵的最直接方法 , 可以從問題的症狀入手, 正向跟蹤或者反向追溯。對於大多數瑕疵 , 使用合適的調試方法可 以大大提高定位到問題根源的效率 。今天的軟件環境在不斷向着大型化 、 並行化、 複雜 化 方向發展 , 定位瑕疵的難度也在隨之不斷提高。 完全靠讀源代碼來尋找 b u g 的方法已經很難適應今天的軟件發展形勢 。 另外 , 枚舉和排除法通常也會因系統中的軟硬件模塊數量太多而難以實施 , 有時候 , 花了幾天時間來做替換仍然找不 到懷疑對象
- 調試可以幫助程序員提高編寫代碼的能力。 因爲調試可以讓程序員徹底瞭解程 序的實際執行過程 , 檢查與自己設計時的預想是否一致 , 如果不一致 , 那麼很可能預示 着有問題存在 , 應該引起重視 。 另外 , 調試過程可以讓程序員更好的認識到提高代碼可調試性和代碼質量的重要性 。 從此 , 自覺的改進編碼方式 , 合理添加用來支持調試的代碼 。編碼和調試是程序員日常工作中的兩個最主要任務 , 這兩個任務是相輔相成的 , 編寫具有可調試性的高質量代碼 , 可以明顯提高調試效率 , 節約調試時間。 另 一方面 , 調試可以讓程序員真切感受程序的實際執行過程 , 反思編碼和設計中的問題 , 加深對軟件和系統的理解 , 提高對代碼的感知力和控制力
- 調試工具是學習計算機系統和其它軟硬件知識的好幫手 。通過軟件調試技術的強大觀察能力和斷點、 棧回溯 、 跟蹤等功能可以快速的瞭解一個軟件和系統的模塊 、 架構 、和工作流程 , 因此是學習其它軟硬件技術的一個快速而有效的方法
Nodejs的debug
使用node啓動時帶上 inspect參數運行,我們可以看到一些提示符,證明調試器已經啓動成功
如果我們將debugger關鍵字放入代碼中,則會在該代碼中的該位置啓用一個斷點
global.x = 5;
setTimeout(() => {
debugger;
console.log('world');
}, 1000);
console.log('hello');
命令名稱 | 命令描述 | 命令快捷鍵 |
---|---|---|
cont | 繼續執行 | c |
next | 單步執行下一行 | n |
step | 單步進入 | s |
out | 單步退出 | o |
backtrace | 打印當前執行框架的回溯 | bt |
pause | 暫停運行中的代碼(累死開發者工具中的暫停按鈕) | 無 |
repl | 打開調試器的repl以在調試腳本的上下文中進行評估 | 無 |
list(5) | 列出具有5行上下文的腳本源代碼(前後5行) | 無 |
watch(expr) | 將表達式添加到監視列表 | 無 |
unwatch(expr) | 從監視列表中刪除表達式 | 無 |
watchers | 列出所有觀察者及其值(在每個斷點處自動列出) | 無 |
exec expr | 在調試腳本的上下文中執行表達式 | 無 |
- V8 Inspector集成允許將Chrome DevTools附加到Node.js實例以進行調試和分析,它使用Chrom DevTools 協議
- –inspect啓動Node.js應用程序時可以通過傳遞標誌來啓用V8檢查器。也可以爲自定義端口提供該標誌,例如,–inspect=9222將接受端口9222上的DevTools連接
以簡易的nodejs http服務爲例 debugger.js
const http = require('http');
http.createServer((req, res) => {
const str = 'Dev Tools Nodejs'
res.end(str);
}).listen(3000);
然後我們使用node --inspect debugger.js,如果需要在應用程序的第一行就終端,則使用–inspect-brk即可
由於我們監聽了3000端口號,故我們在瀏覽器使用localhost:3000訪問,並打開chrom開發者界面,可以看到
我們點擊它,可以看到如下的Chrom Dev Tools界面
我們再重新訪問,可以看到
對於前端開發者來說,可能更傾向於使用瀏覽器來進行調試
但對於大多數開發者來說,編寫JS類代碼,更多的是使用vscode
更多Chrom Dev Tools 相關技巧可以查看https://chromedevtools.github.io/devtools-protocol/
- vscode 調試器 ㅤversion 1.4.5
在下面的演示中,使用了VS Code中文插件
https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-zh-hans
Visual Studio Code的主要功能之一是其強大的調試支持。VS Code的內置調試器有助於加速您的編輯,編譯和調試循環,引用以下官方的圖
- 啓動配置
可以使用快捷鍵F5或者在.vscode下創建lauch.json文件
並且VS Code將嘗試自動檢測您的調試環境,但是如果失敗,則必須手動選擇它,在這裏我們選擇生成nodejs配置文件
以node express爲例
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const example = 'hello express ~~'
res.end(example);
});
app.listen('3000', () => {
console.info('connect to 3000 success ~');
});
字段名稱 | 字段描述 |
---|---|
type | 用於此啓動配置的調試器的類型。每安裝調試擴展引入一個類型:node用於內置節點調試器 |
request | 此啓動配置的請求類型。當前,launch並且attach受支持 |
name | 在調試啓動配置下拉列表中顯示的易於閱讀的名稱 |
presentation | 使用order,group和hidden在屬性 |
presentation | 可以排序,在調試配置下拉菜單,並在調試組,和隱藏的構造和化合物快速挑選對象 |
preLaunchTask | 要在調試會話開始之前啓動任務,請將此屬性設置爲task.json(在工作區的.vscode文件夾中)指定的任務的名稱。或者,可以將其設置${defaultBuildTask}爲使用默認的構建任務 |
postDebugTask | 在調試會話結束時啓動任務,請將此屬性設置爲task.json(在工作區的.vscode文件夾中)指定的任務名稱 |
internalConsoleOptions | 此屬性控制調試會話期間“調試控制檯”面板的可見性 |
debugServer | 僅適用於調試擴展作者:此屬性允許您連接到指定的端口,而不必啓動調試適配器 |
serverReadyAction | 如果要調試的程序在調試控制檯或集成終端上輸出特定消息時,要在Web瀏覽器中打開URL |
program | 啓動調試器時要運行的可執行文件或文件 |
args | 參數傳遞給程序進行調試 |
env | 環境變量(該值null可用於“取消定義”變量) |
cwd | 當前工作目錄,用於查找依賴關係和其他文件 |
port | 連接到正在運行的進程時的端口 |
stopOnEntry | 程序啓動時立即中斷 |
console | 什麼樣的控制檯來使用,例如internalConsole,integratedTerminal或externalTerminal |
vscode會自動識別當前調試環境,自動生成launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "啓動程序",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/app.js"
}
]
}
然後我們使用該配置文件運行
vscode調試動作
- 繼續/暫停F5
- 越過F10
- 進入F11
- 移出Shift + F11
- 重新啓動Ctrl + Shift + F5
- 停止Shift + F5
- 斷點表達式
- 在程序代碼中編輯debug斷點
它只是臨時將表達式添加在代碼中,達到開發者更方便的調試代碼的目的
它由菱形”形狀的圖標表示,且有表達式的斷點可以看到有一個雙橫槓在這裏插入圖片描述
就像常規斷點一樣,可以啓用或禁用對數點,也可以通過條件和/或命中數進行控制
- 在debug控制面板中調試斷點和堆棧
變量可以在“ 運行”視圖的“ 變量”部分中檢查,也可以將鼠標懸停在編輯器中的源上進行檢查。變量值和表達式評估相對於“ 調用堆棧”部分中的選定堆棧幀
可以使用變量的上下文菜單中的“ 設置值”操作來修改變量值
相比較在代碼中調試斷點,在控制面板,我們可以更清晰的看到程序執行的堆棧信息
- 在輸出控制檯下進行調試
可以使用Debug Console REPL(Read-Eval-Print Loop)功能對錶達式求值。要打開調試控制檯,請使用“ 調試”窗格頂部的“ 調試控制檯”操作,或使用“ 查看:調試控制檯”命令(Ctrl + Shift + Y)。按下Enter鍵後,將對錶達式求值,而Debug Console REPL將在您鍵入時顯示建議。如果需要輸入多行,請在各行之間使用Shift + Enter,然後使用Enter發送所有行以進行評估。調試控制檯輸入使用活動編輯器的模式,這意味着調試控制檯輸入支持語法着色,縮進,自動關閉引號和其他語言功能
vscode中的nodejs調試擴展
詳情可以參見官網
https://code.visualstudio.com/docs/nodejs/nodejs-debugging
vscode調試 typescript
VS Code具有對TypeScript調試的內置支持。爲了支持結合執行中的JavaScript代碼調試TypeScript
- 使用tsc編譯執行
- 先安裝typescript
npm install -g typescript
- 查看tsc版本
tsc --version
- 編寫ts文件 app.ts
import * as express from 'express';
const app = express();
app.get('/', (req: any, res: { end: (arg0: string) => void; }) => {
const example = 'hello express ~~'
res.end(example);
});
app.listen('3000', () => {
console.info('connect to 3000 success ~');
});
- 使用tsc將app.ts編譯成js文件
tsc app.ts
- 由於已經編譯成了js文件,此時我們可以使用node命令運行
"use strict";
exports.__esModule = true;
var express = require("express");
var app = express();
app.get('/', function (req, res) {
var example = 'hello express ~~';
res.end(example);
});
app.listen('3000', function () {
console.info('connect to 3000 success ~');
});
node app.js
- 指定tsc配置進行編譯
- 創建tsconfig.json文件並進行簡單的配置
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "out"
}
}
- target 指定ECMAScript目標版本
- module 指定模塊代碼生成類型
- outDir 將輸出結構重定向到目錄
- 使用tsc命令自動編譯當前文件下和子文件夾下的所有ts文件,如果沒有被排查的話
tsc
更多typescript.json配置請查看官方瞭解
使用ts-node執行typescript文件
- ts-node
提供typescript的及時編譯,縮短開發階段的開發時間
npm install -g ts-node
ts-node -v
- 工作原理
ts-node的工作方式是註冊打字稿編譯器.tsx?和.jsx?(當allowJs == true)擴展。當node.js註冊有一個擴展名(通過require.extensions)時,它將在內部使用該擴展名進行模塊解析。當node.js未知擴展名時,它將以.js(JavaScript)處理該文件。
默認情況下,ts-node避免使用/node_modules/以下三種原因來編譯文件:
- 模塊應始終以node.js的格式進行運行
- 編譯整個依賴關係樹會使您的項目變慢
- TypeScript和node.js(例如ES2015模塊)之間的不同行爲可能會導致項目正常運行,直到您決定從node.js本地支持功能
這意味着,如果您不註冊擴展名,它將被編譯爲JavaScript。當ts-node與一起使用時allowJs,將使用TypeScript編譯器來翻譯JavaScript文件
- 加載tsconfig.json
使用ts-node時將會自動加載tsconfig.json。使用–skip-project跳過加載tsconfig.json。
相對於–dir使用與相同的搜索行爲可以解決tsc。在–script-mode中,這是包含腳本的目錄。否則,它是相對於解析的process.cwd(),與的行爲相匹配tsc。
使用–project指定的路徑tsconfig.json,將忽略–dir。
可以ts-node與tsconfig-paths一起使用,根據paths加載tsconfig.json模塊
- 使用ts-node命令運行ts文件
ts-node app.ts
2. 使用ts-node調試ts文件
- 配置tsconfig.json
{
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"outDir": "out"
}
}
- 配置launch.json
{
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/app.ts"
]
}
]
}
- 使用F5或者vscode調試面板啓動
vscode調試egg.js
-
使用egg ts腳手架生成項目
mkdir showcase && cd showcase
npm init egg --type=ts
npm i
npm run dev
- 配置tsconfig.json(egg腳手架已自動生成)
{
"compileOnSave": true,
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"strict": true,
"noImplicitAny": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"charset": "utf8",
"allowJs": false,
"pretty": true,
"noEmitOnError": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"strictPropertyInitialization": false,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"inlineSourceMap": true,
"importHelpers": true
},
"exclude": [
"app/public",
"app/views",
"node_modules*"
]
}
- 使用vscode調試eggjs的四種方式
- 按F1開啓vscode的自動進程附加,然後在端輸入npm run debug開啓調試
- 使用egg官方推薦的launch.json配置啓動debug調試
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Egg",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "npm",
"windows": { "runtimeExecutable": "npm.cmd" },
"runtimeArgs": [ "run", "debug" ],
"console": "integratedTerminal",
"protocol": "auto",
"restart": true,
"port": 9229,
"autoAttachChildProcesses": true
}
]
}
- 使用vscode插件vscode-eggjs生成的launch.json啓動debug調試
選擇egg自動配置launch.json
生成的配置如下
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Egg Debug",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"debug",
"--",
"--inspect-brk"
],
"console": "integratedTerminal",
"restart": true,
"protocol": "auto",
"port": 9229,
"autoAttachChildProcesses": true
},
{
"type": "node",
"request": "launch",
"name": "Egg Test",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"test-local",
"--",
"--inspect-brk"
],
"protocol": "auto",
"port": 9229,
"autoAttachChildProcesses": true
},
{
"type": "node",
"request": "attach",
"name": "Egg Attach to remote",
"localRoot": "${workspaceRoot}",
"remoteRoot": "/usr/src/app",
"address": "localhost",
"protocol": "auto",
"port": 9999
}
]
}
使用F5或者debug控制面板啓動
- 使用vscode的JavaScript Debugger插件啓動
選擇啓動的npm腳本
- 開啓愉快的debug調試之旅~