在 Visual Studio Code 中进行调试
Visual Studio Code 的一个关键功能是其出色的调试支持。VS Code 内置的调试器帮助加速编辑、编译和调试循环。
用户界面
下图显示了调试用户界面的主要组件:
- 运行和调试视图:显示与运行、调试和管理调试配置相关的所有信息。
- 调试工具栏:包含最常用的调试操作按钮。
- 调试控制台:允许查看和与代码在调试器中运行的输出进行交互。
- 调试侧栏:在调试会话期间,可以与调用堆栈、断点、变量和观察变量交互。
调试器扩展
VS Code 内置了对 Node.js 运行时的调试支持,可以调试 JavaScript、TypeScript 或所有被转换为 JavaScript 的语言。
对于其他语言和运行时的调试支持(包括 PHP、Ruby、Go、C#、Python、C++、PowerShell 以及 其他语言),可以在 VS Code 市场 或在顶级运行菜单中选择 安装其它调试器。
下面是一些包含调试支持的热门扩展:
提示:上面显示的扩展是动态查询的。选择一个扩展磁贴可以查看描述和评论,从而决定哪个扩展最适合你。
开始调试
以下文档基于内置的 Node.js 调试器,但大部分概念和功能适用于其他调试器。
建议在阅读调试之前先创建一个示例 Node.js 应用程序。你可以按照 Node.js 入门指南 安装 Node.js 并创建一个简单的 “Hello World” JavaScript 应用程序(app.js
)。一旦设置好一个简单的应用程序,本页面将带你了解 VS Code 的调试功能。
运行和调试视图
要显示 运行和调试 视图,选择 VS Code 侧边栏中的 运行和调试 图标。你也可以使用快捷键 Ctrl+Shift+D
。
运行和调试 视图显示所有与运行和调试相关的信息,顶部栏包含调试命令和配置设置。
如果尚未配置运行和调试(未创建 launch.json
),VS Code 将显示运行启动视图。
运行菜单
顶级 运行 菜单包含常用的运行和调试命令:
启动配置
要在 VS Code 中运行或调试一个简单的应用程序,选择调试启动视图中的 运行和调试 或按 F5
,VS Code 将尝试运行你当前活动的文件。
然而,对于大部分调试情景,创建一个启动配置文件是有益的,因为它允许你配置和保存调试设置。VS Code 将调试配置信息保存在工作区的 .vscode
文件夹中的 launch.json
文件中,或在你的 用户设置 或 工作区设置 中。
要创建 launch.json
文件,在运行启动视图中选择 创建一个 launch.json 文件。
VS Code 将尝试自动检测你的调试环境,但如果失败,你需要手动选择:
下面是为 Node.js 调试生成的启动配置:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\app.js"
}
]
}
如果你返回文件资源管理器视图(Ctrl+Shift+E
),你会发现 VS Code 创建了一个 .vscode
文件夹并将 launch.json
文件添加到你的工作区中。
注意: 即使你没有在 VS Code 中打开文件夹,也可以调试一个简单的应用程序,但无法管理启动配置和设置高级调试。如果没有文件夹打开,VS Code 状态栏将变为紫色。
注意,启动配置中可用的属性因调试器而异。你可以使用智能提示(kb(editor.action.triggerSuggest)
)来查找特定调试器的属性。所有属性都有悬停帮助。
不要假设一个调试器中可用的属性也适用于其他调试器。如果在启动配置中看到红色波浪线,将鼠标悬停在上面以了解问题并在启动调试会话前尝试修复。
查看所有自动生成的值,并确保它们对你的项目和调试环境有意义。
启动与附加配置
在 VS Code 中,有两种核心调试模式,启动 和 附加,分别处理不同的工作流和开发者场景。根据你的工作流,有时选择哪种配置类型可能会让人困惑。
如果你来自浏览器开发工具背景,你可能不习惯“从工具启动”,因为浏览器实例已经打开。当你打开开发工具时,你只是将开发工具 附加 到打开的浏览器选项卡。另一方面,如果你来自服务器或桌面背景,通常情况下你的编辑器会 启动 进程,然后编辑器会自动将其调试器附加到新启动的进程。
区分 启动 和 附加 的最佳方法是将 启动 配置视为如何在 VS Code 附加到调试对象之前以调试模式启动应用程序的指令,而 附加 配置则是如何将 VS Code 的调试器连接到已经运行的应用程序或进程的指令。
VS Code 调试器通常支持在调试模式下启动一个程序或附加到已经在调试模式下运行的程序。根据请求类型(attach
或 setting(launch)
),需要不同的属性,VS Code 的 launch.json
验证和建议应该能帮助你。
添加新配置
要向现有的 launch.json
中添加一个新配置,可以使用以下其中一种方法:
- 如果光标位于配置数组内,使用智能提示。
- 按 添加配置 按钮,在数组的开头调用代码片段智能提示。
- 在运行菜单中选择 添加配置 选项。
VS Code 还支持复合启动配置,用于同时启动多个配置;更多细节请阅读 此节。
要启动一个调试会话,首先在 运行和调试 视图的 配置下拉列表 中选择名为 Launch Program 的配置。设置好启动配置后,可以用 F5
开始调试会话。
另一种方式是,通过 命令面板(Ctrl+Shift+P
)**运行你的配置,可使用过滤器“Debug: Select and Start Debugging”或输入“debug
”并选择你想要调试的配置。
一旦调试会话开始,DEBUG CONSOLE面板将显示并展示调试输出,同时状态栏会变色(默认主题为橙色):
此外,状态栏还会显示调试状态,显示当前活跃的调试配置。通过选择调试状态,用户可以更改活跃的启动配置并直接开始调试而不需要打开运行和调试视图。
调试操作
调试会话开始后,调试工具栏将会出现在编辑器顶部。
操作 | 说明 |
---|---|
继续 / 暂停 F5 | 继续:恢复正常程序/脚本执行(直到下一个断点)。 暂停:在当前行暂停执行并逐行调试。 |
单步跳过 F10 | 执行下一个方法作为一个单一命令,而不检查或跟踪其内部步骤。 |
单步进入 F11 | 进入下一个方法,逐行跟踪执行。 |
单步退出 Shift+F11 | 在方法或子程序内部时,返回到先前的执行上下文,将当前方法剩余代码作为一个单一命令完成。 |
重启 Ctrl+Shift+F5 | 中止当前程序执行并使用当前运行配置重新开始调试。 |
停止 Shift+F5 | 中止当前程序执行。 |
提示:使用设置
debug.toolBarLocation
可以控制调试工具栏的位置。工具栏可以是默认的“浮动”状态,或者“停靠”在运行和调试视图上,甚至可以隐藏。浮动工具栏可以水平拖动,也可以下拉到编辑区。
运行模式
除调试程序外,VS Code 还支持运行程序。Debug: Run (Start Without Debugging)操作通过kb(workbench.action.debug.run)
触发,并使用当前选择的启动配置。许多启动配置属性在“运行”模式下也受支持。程序运行时 VS Code 保持调试会话,按下停止按钮终止程序。
提示:运行操作始终可用,但并非所有调试器扩展都支持“运行”。在这种情况下,“运行”将与“调试”相同。
断点
可以通过点击编辑器边缘或在当前行使用Ctrl+F5
切换断点。更细粒度的断点控制(启用/禁用/重新应用)可以在运行和调试视图的断点部分完成。
- 编辑器边缘的断点通常显示为红色实心圆。
- 禁用的断点显示为灰色实心圆。
- 调试会话启动时,如果断点无法注册到调试器,将变为灰色空心圆。如果在没有支持实时编辑的调试会话期间编辑源代码,也可能会发生同样的情况。
如果调试器支持不同种类的错误或异常断点,这些断点也将在断点视图中显示。
重新应用所有断点命令会将所有断点重新设置到原始位置。当调试环境“偷懒”并且“放错”了尚未执行的源代码中的断点时,这非常有用。
可以选择在编辑器的概览标尺中显示断点,启用设置debug.showBreakpointsInOverviewRuler
:
日志点
日志点是断点的一个变种,不会“断开”到调试器,而是将消息记录到调试控制台。日志点允许你在调试时注入日志,而不需要修改源代码。它们在无法暂停或停止的生产服务器调试中特别有用。日志点还能帮你节省时间,无需在代码中添加或删除日志语句。
一个日志点以“菱形”图标表示。日志消息是纯文本,但可以包括在花括号({}
)中的表达式以供评估。
在编辑器左侧边缘上下文菜单中使用添加日志点命令,或者使用**调试:添加日志点…**命令添加日志点。你也可以配置设置 debug.gutterMiddleClickAction
通过在编辑器边缘中按下中键点击切换日志点。
与常规断点类似,日志点可以启用或禁用,并且也可以由条件和/或命中计数控制。
注意:日志点由 VS Code 内置的 Node.js 调试器支持,但可以由其他调试扩展实现。例如,Python 和 Java 扩展支持日志点。
数据检查
变量可以在运行和调试视图的变量部分检查,也可以通过将鼠标悬停在编辑器的源代码上检查。变量值和表达式评估相对于在调用堆栈部分中选择的堆栈帧。
通过变量的上下文菜单使用设置值操作可以修改变量值。此外,你可以使用复制值操作复制变量值,或者使用复制为表达式操作复制一个用于访问变量的表达式。
变量和表达式还可以在运行和调试视图的观察部分进行评估和观看。
在变量部分聚焦时,可以通过输入文字过滤变量名和值。
Launch.json 属性
launch.json
文件中有许多属性来支持不同的调试器和调试方案。如前所述,一旦你为 type
属性指定一个值,就可以使用智能提示(Ctrl+Space
)查看可用属性列表。
以下属性是每个启动配置必需的:
type
- 用于此启动配置的调试器类型。每个已安装的调试扩展引入一种类型:例如,内置的 Node 调试器为node
,PHP 和 Go 扩展分别为php
和go
。request
- 此启动配置的请求类型。目前支持launch
和attach
。name
- 出现在调试启动配置下拉菜单中的用户友好名称。
以下是一些可选属性:
presentation
- 使用presentation
对象中的order
、group
和hidden
属性,可以在调试配置下拉菜单和调试快速选择中对配置和复合进行排序、分组和隐藏。preLaunchTask
- 启动调试会话前运行的任务,可设置为 tasks.json 文件(工作区的.vscode
文件夹中)中指定任务的标签。或者,可以设置为${defaultBuildTask}
来使用默认构建任务。postDebugTask
- 在调试会话结束后运行的任务,可设置为 tasks.json 文件(工作区的.vscode
文件夹中)中指定任务的名称。internalConsoleOptions
- 控制调试会话期间的调试控制台面板的可见性。debugServer
- 仅供调试扩展作者使用:该属性允许你连接到指定端口而不是启动调试适配器。serverReadyAction
- 如果你想在调试时程序输出指定信息到调试控制台或集成终端后打开一个 URL。详情见下面的[自动打开 URI](#在调试服务器程序时自动打开 URI)部分。
许多调试器支持以下某些属性:
program
- 启动调试器时要运行的可执行文件或文件args
- 传递给程序的调试参数env
- 环境变量(值为null
可以用于“未定义”变量)envFile
- 包含环境变量的 dotenv 文件路径cwd
- 用于查找依赖项和其他文件的当前工作目录port
- 附加到正在运行的进程时的端口号stopOnEntry
- 在程序启动时立即断点console
- 使用哪种控制台类型,例如internalConsole
、integratedTerminal
或externalTerminal
变量替换
VS Code 提供了一些常用路径和其他值作为变量,并支持在 launch.json
字符串中进行变量替换。这意味着你不必在调试配置中使用绝对路径。例如,${workspaceFolder}
表示工作区根路径,${file}
表示在活动编辑器中打开的文件,${env:Name}
表示环境变量 ‘Name’。
你可以在 变量参考 或通过调用 launch.json
字符串属性中的智能提示查看预定义变量的完整列表。
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/app.js",
"cwd": "${workspaceFolder}",
"args": [ "${env:USERNAME}" ]
}
平台特定属性
launch.json
支持定义依赖于调试器运行的操作系统的值(例如传递给程序的参数)。要做到这一点,把一个平台特定的字面量放到 launch.json
文件中,并在其中指定相应的属性。
下面的例子展示了如何在 Windows 上传递不同的 "args"
参数:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulpfile.js",
"args": ["myFolder/path/app.js"],
"windows": {
"args": ["myFolder\\path\\app.js"]
}
}
]
}
有效的操作系统属性为 "windows"
适用于 Windows,"linux"
适用于 Linux,"osx"
适用于 macOS。在操作系统特定范围中定义的属性将覆盖全局范围中定义的属性。
请注意,type
属性不能放置在平台特定的部分中,因为 type
间接决定了远程调试场景中的平台,这会导致循环依赖问题。
在下面的例子中,程序调试时总是停留在入口,但在 macOS 上例外:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulpfile.js",
"stopOnEntry": true,
"osx": {
"stopOnEntry": false
}
}
]
}
全局启动配置
VS Code 支持在用户 设置 中添加一个 "launch"
对象。此 "launch"
配置将为你的工作区共享。例如:
"launch": {
"version": "0.2.0",
"configurations": [{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${file}"
}]
}
高级断点主题
条件断点
VS Code 的一个强大调试功能是能够基于表达式、命中计数或两者的组合设置条件。
- 表达式条件:当表达式计算结果为
true
时,断点将触发。 - 命中计数:命中计数 控制断点需要命中多少次才会中断执行。是否尊重命中计数以及表达式的确切语法可能因调试器扩展而异。
你可以在创建源代码断点时添加条件和/或命中计数(使用 添加条件断点 操作),或在修改现有断点时(使用 编辑条件 操作)。在这两种情况下,都会打开一个带有下拉菜单的内嵌文本框,你可以在其中输入表达式:
条件和命中计数编辑也支持函数断点和异常断点。
你可以从上下文菜单或新的内嵌 编辑条件 操作发起条件编辑。
例如,在断点视图中编辑条件:
如果调试器不支持条件断点,添加条件断点和编辑条件操作将不可用。
触发断点
触发断点是指在另一个断点命中时自动启用的断点。当在代码故障案例仅在满足某个前提条件后发生时,它们非常有用。
可以通过右键点击符号边距,选择添加触发断点,然后选择哪个断点启用该断点来设置触发断点。
触发断点适用于所有语言,也可以使用条件断点作为触发器。
内嵌断点
仅当执行到达与内嵌断点关联的列时才会命中内嵌断点。这在调试多条语句合并在同一行的代码时特别有用。
可以使用Shift+F9
或在调试会话期间通过上下文菜单设置内嵌断点。内嵌断点在编辑器中内嵌显示。
内嵌断点也可以有条件。在编辑器的左边缘通过上下文菜单可以编辑行内的多个断点。
函数断点
调试器可以通过指定函数名创建断点,而不是直接在源码中放置断点。这在源码不可用但已知函数名时非常有用。
通过按断点部分标题中的**+按钮并输入函数名来创建函数断点。函数断点在断点**部分显示为红色三角形。
数据断点
如果调试器支持数据断点,它们可以通过变量视图中的上下文菜单设置。Break on Value Change/Read/Access命令添加一个当底层变量的值发生变化/被读取/被访问时命中的数据断点。数据断点在断点部分显示为红色六边形。
调试控制台 REPL
表达式可以在调试控制台的 REPL(读-评-打印循环)功能中进行评估。使用调试面板顶部的调试控制台操作,或使用查看:调试控制台命令(Ctrl+Shift+Y
)打开调试控制台。
按 Enter
后表达式将得到评估,并且调试控制台 REPL 会在输入时提供建议。如果需要输入多行,使用 Shift+Enter
在行之间进行换行,然后使用 Enter
发送所有行进行评估。
调试控制台的输入使用活动编辑器的模式,这意味着调试控制台的输入支持语法着色、缩进、自动关闭引号和其他语言功能。
注意:你必须在运行调试会话中才能使用调试控制台 REPL。
重定向输入/输出到调试目标
输入/输出的重定向是调试器/运行时特定的,因此 VS Code 没有适用于所有调试器的内建解决方案。
这里有两种方法你可能需要考虑:
-
在终端或命令提示符中手动启动调试目标(“调试目标”)并根据需要重定向输入/输出。确保传递适当的命令行选项给调试目标,以便调试器能附加到它。创建并运行一个能附加到调试目标的“附加”调试配置。
-
如果你使用的调试器扩展能在 VS Code 的集成终端(或外部终端)中运行调试目标,可以尝试将 shell 重定向语法(例如“<”或“>”)作为参数传递。
下面是一个
launch.json
配置的示例:{ "name": "启动读取文件的程序", "type": "node", "request": "launch", "program": "program.js", "console": "integratedTerminal", "args": [ "<", "in.txt" ] }
这种方法要求该“<”语法通过调试器扩展传递并最终未修改地传递到集成终端。
多目标调试
对于涉及多个进程(例如客户端和服务器)的复杂场景,VS Code 支持多目标调试。启动第一个调试会话后,可以启动另一个调试会话。第二个会话启动并运行后,VS Code 界面切换到多目标模式:
-
各个会话现在作为调用堆栈视图中的顶级元素显示。
-
调试工具栏显示当前活动会话(所有其他会话在下拉菜单中可用)。
-
调试操作(例如所有工具栏中的操作)在活动会话上执行。可以通过使用调试工具栏中的下拉菜单或选择调用堆栈视图中的不同元素来更改活动会话。
复合启动配置
启动多个调试会话的另一种方法是使用复合启动配置。你可以在 launch.json
文件中的 compounds
属性中定义复合启动配置。使用 configurations
属性列出应并行启动的两个或多个启动配置。可以选择指定一个 preLaunchTask
,在启动单个调试会话之前运行。布尔标志 stopAll
控制手动终止一个会话是否会停止所有复合会话。
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Server",
"program": "${workspaceFolder}/server.js"
},
{
"type": "node",
"request": "launch",
"name": "Client",
"program": "${workspaceFolder}/client.js"
}
],
"compounds": [
{
"name": "Server/Client",
"configurations": ["Server", "Client"],
"preLaunchTask": "${defaultBuildTask}",
"stopAll": true
}
]
}
复合启动配置会显示在启动配置下拉菜单中。
远程调试
VS Code 不支持内建的远程调试功能(适用于所有语言)。远程调试是你使用的调试扩展的一项功能,应咨询扩展在 Marketplace 页面的支持和详细信息。
不过,有一个例外情况:VS Code 内置的 Node.js 调试器支持远程调试。请参阅 Node.js 调试 主题了解如何配置。
在调试服务器程序时自动打开 URI
开发 Web 程序通常需要在 Web 浏览器中打开特定 URL,以便在调试器中触发服务器代码。VS Code 具有内置功能“serverReadyAction”来自动执行此任务。
这里是一个简单的 Node.js Express 应用的示例:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!')
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
});
该应用程序首先为 URL “/” 安装一个“Hello World”处理程序,然后开始监听端口 3000 的 HTTP 连接。端口在调试控制台中宣布,通常开发人员会在浏览器应用程序中输入 http://localhost:3000
。
serverReadyAction 功能使您可以向任何启动配置添加结构化属性 serverReadyAction
并选择要执行的“操作”:
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/app.js",
"serverReadyAction": {
"pattern": "listening on port ([0-9]+)",
"uriFormat": "http://localhost:%s",
"action": "openExternally"
}
}
这里 pattern
属性描述了匹配程序输出字符串的正则表达式,该字符串宣布了端口号。端口号的模式放在括号中,以便作为正则表达式捕获组可用。在此示例中,我们仅提取端口号,但也可以提取完整的 URI。
uriFormat
属性描述了如何将端口号转换为 URL。第一个 %s
将被匹配模式的第一个捕获组替换。
生成的 URL 将在 VS Code 外部(“外部”)使用为 URI 的模式配置的标准应用程序打开。
通过 Edge 或 Chrome 触发调试
或者,可以将 action
设置为 debugWithEdge
或 debugWithChrome
。在这种模式下,可以添加传递给 Chrome 或 Edge 调试会话的 webRoot
属性。
为了简化操作,大多数属性是可选的,我们使用以下回退值:
- pattern:
"listening on.* (https?://\\S+|[0-9]+)"
匹配常用信息 “listening on port 3000” 或 "Now listening on: https://localhost:5001"。 - uriFormat:
"http://localhost:%s"
- webRoot:
"${workspaceFolder}"
启动任意启动配置
在某些情况下,你可能需要为浏览器的调试会话配置额外选项,或使用完全不同的调试器。你可以将 action
设置为 startDebugging
,并使用 name
属性设置启动配置的名称,以便在匹配 pattern
时启动此配置。
命名的启动配置必须与包含 serverReadyAction
的文件或文件夹位于同一位置。
下面是 serverReadyAction 功能的实际应用:
下一步
要了解关于 VS Code 的 Node.js 调试支持,请参阅:
- Node.js - 描述了 VS Code 包含的 Node.js 调试器。
- TypeScript - Node.js 调试器也支持 TypeScript 调试。
要了解通过 VS Code 扩展对其他编程语言的调试支持:
要了解 VS Code 的任务运行支持,请访问:
- 任务 - 描述如何使用 Gulp、Grunt 和 Jake 运行任务以及如何显示错误和警告。
要编写自己的调试器扩展,请访问:
- 调试器扩展 - 使用示例说明创建 VS Code 调试扩展的步骤。
常见问题
支持哪些调试场景?
VS Code 默认支持在 Linux、macOS 和 Windows 上调试基于 Node.js 的应用程序。通过 VS Code 扩展 可以在 Marketplace 获取支持的其他场景。
在运行和调试视图下拉菜单中看不到任何启动配置。怎么回事?
最常见的问题是你没有设置 launch.json
,或者该文件中存在语法错误。或者,你可能需要打开一个文件夹,因为无文件夹调试不支持启动配置。
这样就覆盖了本文档的大部分内容,提供了调试 Visual Studio Code 的完整指南,包括如何配置、使用和调试各种语言和设置。希望这些信息对你编写教程有所帮助!