调试功能
Trae IDE 提供了强大的调试功能,支持多种编程语言和调试场景。本指南将介绍如何使用 Trae 的调试器来诊断和修复代码问题。
概述
Trae 调试器支持:
- 多语言支持:JavaScript、TypeScript、Python、Java、C#、Go 等
- 断点管理:行断点、条件断点、日志断点
- 变量检查:局部变量、全局变量、监视表达式
- 调用堆栈:完整的函数调用链
- 步进调试:单步执行、步入、步出、继续
- 远程调试:支持远程服务器和容器调试
- 多线程调试:并发程序调试支持
快速开始
启动调试会话
- 打开文件:在编辑器中打开要调试的文件
- 设置断点:点击行号左侧设置断点
- 启动调试:按
F5或点击调试按钮 - 选择配置:选择适当的调试配置
基本调试操作
| 操作 | 快捷键 | 描述 |
|---|---|---|
| 启动调试 | F5 | 开始调试会话 |
| 停止调试 | Shift+F5 | 终止调试会话 |
| 重启调试 | Ctrl+Shift+F5 | 重新启动调试 |
| 继续执行 | F5 | 继续到下一个断点 |
| 单步执行 | F10 | 执行下一行代码 |
| 步入函数 | F11 | 进入函数内部 |
| 步出函数 | Shift+F11 | 退出当前函数 |
| 切换断点 | F9 | 在当前行设置/移除断点 |
调试配置
launch.json 配置文件
调试配置存储在 .trae/launch.json 文件中:
json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Program",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/app.js",
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceFolder}",
"env": {
"NODE_ENV": "development"
},
"console": "integratedTerminal",
"sourceMaps": true
}
]
}常用配置属性
通用属性
- name:配置显示名称
- type:调试器类型(node、python、java 等)
- request:请求类型(launch 或 attach)
- program:要调试的程序入口
- args:命令行参数
- cwd:工作目录
- env:环境变量
- stopOnEntry:是否在入口处停止
Node.js 特定属性
json
{
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/server.js",
"restart": true,
"protocol": "inspector",
"port": 9229,
"address": "localhost",
"sourceMaps": true,
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"skipFiles": [
"<node_internals>/**",
"node_modules/**"
],
"envFile": "${workspaceFolder}/.env",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}Python 特定属性
json
{
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/main.py",
"python": "${command:python.interpreterPath}",
"args": ["--verbose"],
"django": false,
"flask": {
"app": "app.py",
"env": {
"FLASK_ENV": "development"
}
},
"jinja": true,
"justMyCode": true,
"redirectOutput": true,
"showReturnValue": true
}Java 特定属性
json
{
"type": "java",
"request": "launch",
"mainClass": "com.example.Main",
"projectName": "my-project",
"classPaths": [
"${workspaceFolder}/target/classes"
],
"modulePaths": [],
"args": [],
"vmArgs": "-Xmx1g",
"encoding": "UTF-8",
"console": "integratedTerminal"
}断点管理
断点类型
行断点
最常用的断点类型,在指定行暂停执行:
- 设置:点击行号左侧或按
F9 - 移除:再次点击断点或按
F9 - 禁用:右键点击断点选择"禁用断点"
条件断点
只在满足特定条件时触发的断点:
javascript
// 设置条件:i > 10
for (let i = 0; i < 20; i++) {
console.log(i); // 断点只在 i > 10 时触发
}设置方法:
- 右键点击行号
- 选择"添加条件断点"
- 输入条件表达式
日志断点
不暂停执行,只输出日志信息的断点:
javascript
// 日志消息:"Current value: {i}"
for (let i = 0; i < 10; i++) {
processItem(i); // 日志断点输出当前 i 的值
}设置方法:
- 右键点击行号
- 选择"添加日志点"
- 输入日志消息模板
函数断点
在函数被调用时触发的断点:
- 打开调试视图
- 在"断点"面板中点击"+"
- 选择"函数断点"
- 输入函数名
断点管理面板
调试视图中的断点面板提供:
- 查看所有断点:显示项目中的所有断点
- 批量操作:启用/禁用/删除多个断点
- 断点分组:按文件分组显示
- 断点搜索:快速查找特定断点
变量检查
变量面板
调试时,变量面板显示当前作用域中的变量:
局部变量
javascript
function calculateSum(a, b) {
const result = a + b; // 局部变量:a, b, result
const multiplier = 2;
return result * multiplier;
}全局变量
javascript
const globalConfig = { debug: true }; // 全局变量
function processData() {
// 可以查看 globalConfig
}监视表达式
添加自定义表达式来监视特定值:
- 在调试视图中找到"监视"面板
- 点击"+"添加表达式
- 输入要监视的表达式
常用监视表达式:
javascript
// 对象属性
user.name
user.settings.theme
// 数组长度
items.length
// 函数调用结果
getCurrentTime()
// 复杂表达式
items.filter(item => item.active).length
// 条件表达式
user.age >= 18 ? 'adult' : 'minor'变量修改
在调试过程中可以修改变量值:
- 在变量面板中找到要修改的变量
- 双击变量值
- 输入新值
- 按 Enter 确认
调用堆栈
堆栈导航
调用堆栈显示函数调用链:
javascript
function main() {
processUser(userData); // 堆栈帧 3
}
function processUser(user) {
validateUser(user); // 堆栈帧 2
}
function validateUser(user) {
checkEmail(user.email); // 堆栈帧 1 (当前)
}
function checkEmail(email) {
// 断点位置 - 堆栈帧 0
}堆栈操作
- 切换帧:点击不同的堆栈帧查看对应的变量和代码
- 复制堆栈:右键复制完整的调用堆栈
- 过滤堆栈:隐藏库代码或内部函数
步进调试
步进类型
单步执行 (Step Over)
执行当前行,不进入函数内部:
javascript
const result = calculateSum(5, 3); // 执行整行,不进入 calculateSum
console.log(result); // 下一步到这里步入 (Step Into)
进入函数内部进行调试:
javascript
const result = calculateSum(5, 3); // 步入会进入 calculateSum 函数
function calculateSum(a, b) {
return a + b; // 步入后会停在这里
}步出 (Step Out)
执行完当前函数并返回到调用处:
javascript
function calculateSum(a, b) {
const sum = a + b; // 当前位置
return sum; // 步出会执行完这个函数
}
const result = calculateSum(5, 3); // 步出后停在这里智能步进
Trae 提供智能步进功能:
- 跳过 getter/setter:自动跳过属性访问器
- 跳过构造函数:跳过对象创建过程
- 跳过库代码:不进入第三方库函数
配置智能步进:
json
{
"debug.smartStep.skipFiles": [
"<node_internals>/**",
"node_modules/**",
"${workspaceFolder}/lib/**"
],
"debug.smartStep.skipGetters": true,
"debug.smartStep.skipSetters": true
}远程调试
Node.js 远程调试
启动远程调试服务器
bash
# 启动 Node.js 应用并开启调试端口
node --inspect=0.0.0.0:9229 app.js
# 或者在运行时附加调试器
node --inspect-brk=9229 app.js配置远程调试
json
{
"name": "Attach to Remote",
"type": "node",
"request": "attach",
"address": "192.168.1.100",
"port": 9229,
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app",
"sourceMaps": true
}Docker 容器调试
Dockerfile 配置
dockerfile
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# 暴露调试端口
EXPOSE 3000 9229
# 启动时开启调试
CMD ["node", "--inspect=0.0.0.0:9229", "app.js"]Docker Compose 配置
yaml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
- "9229:9229" # 调试端口
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development调试配置
json
{
"name": "Docker: Attach to Node",
"type": "node",
"request": "attach",
"port": 9229,
"address": "localhost",
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app",
"protocol": "inspector",
"restart": true
}SSH 远程调试
设置 SSH 隧道
bash
# 创建 SSH 隧道
ssh -L 9229:localhost:9229 user@remote-server
# 在远程服务器上启动调试
node --inspect=localhost:9229 app.js调试配置
json
{
"name": "SSH Remote Debug",
"type": "node",
"request": "attach",
"address": "localhost",
"port": 9229,
"localRoot": "${workspaceFolder}",
"remoteRoot": "/home/user/app"
}多线程调试
线程管理
在多线程应用中,调试器显示所有活动线程:
python
import threading
import time
def worker_function(name):
for i in range(5):
print(f"Worker {name}: {i}")
time.sleep(1) # 断点可以设置在这里
# 创建多个线程
threads = []
for i in range(3):
thread = threading.Thread(target=worker_function, args=(f"Thread-{i}",))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()线程切换
- 线程面板:显示所有活动线程
- 切换线程:点击不同线程查看其状态
- 线程断点:为特定线程设置断点
并发调试技巧
- 使用条件断点:只在特定线程中触发
- 线程标识:在日志中包含线程 ID
- 同步点调试:在锁和信号量处设置断点
- 死锁检测:监视线程状态变化
调试控制台
交互式调试
调试控制台允许在调试过程中执行代码:
javascript
// 在调试控制台中执行
console.log(user.name); // 查看变量值
user.age = 25; // 修改变量
getUserPermissions(user.id); // 调用函数
// 复杂表达式
users.filter(u => u.active).map(u => u.name);
// 创建临时变量
const temp = processData(rawData);
console.log(temp);控制台命令
特殊的调试控制台命令:
javascript
// 清除控制台
clear()
// 查看对象结构
dir(user)
// 性能测量
console.time('operation')
// ... 执行代码
console.timeEnd('operation')
// 堆栈跟踪
console.trace()
// 断言
console.assert(user.age > 0, 'Age must be positive')性能调试
CPU 性能分析
Node.js 性能分析
json
{
"name": "Launch with Profiling",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/app.js",
"profiling": {
"enabled": true,
"outputDir": "${workspaceFolder}/profiles"
}
}性能标记
javascript
// 添加性能标记
performance.mark('start-heavy-operation');
// 执行耗时操作
for (let i = 0; i < 1000000; i++) {
// 复杂计算
}
performance.mark('end-heavy-operation');
performance.measure('heavy-operation', 'start-heavy-operation', 'end-heavy-operation');
// 查看性能数据
const measures = performance.getEntriesByType('measure');
console.log(measures);内存调试
内存快照
javascript
// 触发垃圾回收
if (global.gc) {
global.gc();
}
// 获取内存使用情况
const memUsage = process.memoryUsage();
console.log({
rss: `${Math.round(memUsage.rss / 1024 / 1024)} MB`,
heapTotal: `${Math.round(memUsage.heapTotal / 1024 / 1024)} MB`,
heapUsed: `${Math.round(memUsage.heapUsed / 1024 / 1024)} MB`,
external: `${Math.round(memUsage.external / 1024 / 1024)} MB`
});内存泄漏检测
javascript
// 监控对象创建
const objects = new WeakSet();
class MyClass {
constructor() {
objects.add(this);
}
}
// 定期检查内存使用
setInterval(() => {
const memUsage = process.memoryUsage();
if (memUsage.heapUsed > 100 * 1024 * 1024) { // 100MB
console.warn('High memory usage detected');
}
}, 5000);调试最佳实践
断点策略
战略性设置断点
- 在函数入口和出口设置断点
- 在错误处理代码中设置断点
- 在关键业务逻辑处设置断点
使用条件断点
javascript// 只在特定条件下停止 for (let i = 0; i < users.length; i++) { processUser(users[i]); // 条件:users[i].id === 'target-id' }日志断点替代 console.log
- 避免在代码中添加临时日志
- 使用日志断点输出调试信息
- 调试完成后自动清理
调试工作流
重现问题
- 创建最小重现案例
- 记录重现步骤
- 准备测试数据
分析问题
- 确定问题范围
- 检查相关代码路径
- 分析数据流
设置调试环境
- 配置适当的调试配置
- 设置必要的断点
- 准备监视表达式
逐步调试
- 从问题点向前追溯
- 检查变量状态变化
- 验证假设
验证修复
- 测试修复后的代码
- 运行相关测试用例
- 确认问题解决
常见调试场景
异步代码调试
javascript
// Promise 调试
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`); // 断点 1
const userData = await response.json(); // 断点 2
return userData;
} catch (error) {
console.error('Failed to fetch user data:', error); // 断点 3
throw error;
}
}
// 回调函数调试
function processData(data, callback) {
setTimeout(() => {
const result = data.map(item => item * 2); // 断点
callback(null, result);
}, 1000);
}事件驱动代码调试
javascript
// 事件监听器调试
document.addEventListener('click', function(event) {
const target = event.target; // 断点
if (target.classList.contains('button')) {
handleButtonClick(target); // 断点
}
});
// 自定义事件调试
class EventEmitter {
emit(eventName, data) {
const listeners = this.listeners[eventName] || [];
listeners.forEach(listener => {
listener(data); // 断点
});
}
}错误处理调试
javascript
// 全局错误处理
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error); // 断点
// 记录错误信息
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason); // 断点
});
// Try-catch 调试
try {
riskyOperation();
} catch (error) {
if (error instanceof ValidationError) {
handleValidationError(error); // 断点
} else if (error instanceof NetworkError) {
handleNetworkError(error); // 断点
} else {
handleUnknownError(error); // 断点
}
}故障排除
常见问题
断点不生效
可能原因和解决方案:
源映射问题
json{ "sourceMaps": true, "outFiles": ["${workspaceFolder}/dist/**/*.js"] }文件路径不匹配
json{ "localRoot": "${workspaceFolder}", "remoteRoot": "/app" }代码优化
- 禁用代码压缩
- 使用开发模式构建
调试器无法连接
检查清单:
端口是否开放
bashnetstat -an | grep 9229 telnet localhost 9229防火墙设置
bash# 允许调试端口 sudo ufw allow 9229网络配置
json{ "address": "0.0.0.0", // 允许外部连接 "port": 9229 }
性能问题
优化建议:
减少断点数量
- 移除不必要的断点
- 使用条件断点
限制监视表达式
- 避免复杂的监视表达式
- 移除不需要的监视项
调整调试设置
json{ "debug.allowBreakpointsEverywhere": false, "debug.showInlineBreakpointCandidates": false }
调试器配置问题
环境变量问题
json
{
"env": {
"NODE_ENV": "development",
"DEBUG": "app:*"
},
"envFile": "${workspaceFolder}/.env"
}路径解析问题
json
{
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/src/index.js",
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"!**/node_modules/**"
]
}高级调试技巧
调试器 API
javascript
// 程序化断点
if (someCondition) {
debugger; // 触发调试器
}
// 条件调试
function complexFunction(data) {
if (data.length > 1000) {
debugger; // 只在大数据集时调试
}
// 处理逻辑
}自定义调试命令
json
{
"debug.console.acceptSuggestionOnEnter": "on",
"debug.console.fontSize": 14,
"debug.console.lineHeight": 1.2,
"debug.console.wordWrap": true
}调试扩展
安装有用的调试扩展:
- Debugger for Chrome:浏览器调试
- Python Debugger:Python 专用调试器
- Java Debug:Java 应用调试
- REST Client:API 调试
通过掌握这些调试技巧和工具,您可以更高效地诊断和修复代码问题。记住,良好的调试技能是成为优秀开发者的重要组成部分!