调试

vscode的一个关键特性是它的强大的调试支持。vscode的内置调试可以帮助加速你的编辑,编译和调试的循环。

vscode chorem调试 vscode调试功能_调试器

调试器插件

vscode内置的调试支持Node.js运行时,可以调试JavaScript, TypeScript和其他能够转换成JavaScript的语言。

为了调试其他语言和运行时(包括PHP, Ruby, Go, C#, Python, C++, PowerShell和其他许多),可以在vscode市场里查找调试器插件或者在顶层Run菜单选择安装其他调试器。

下面是几个常用的包含调试支持的插件:

python: https://marketplace.visualstudio.com/items?itemName=ms-python.python

C/C++: https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools

C#: https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp

Debugger for Chrome: https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome

提示:上面的插件都是动态查询的,选择一个插件去阅读描述,然后审核一下决定哪个插件最适合你。

 

开始调试

下面描述主要是基于内置的Node.js调试器,但是大部分内容和特性也适合其他调试器。

在阅读调试之前创建一个Node.js示例应用是有帮助的。你可以跟着Node.js walkthrough(https://code.visualstudio.com/docs/nodejs/nodejs-tutorial)去安装Node.js和创建一个简单的“Hello World” JavaScript应用(app.js)。一旦你了这个简单的应用设置,这篇文章将带你通过vscode的调试特性。

Run view(运行视图)

为了显示运行视图,在vscode边上的Activity Bar(一般在最左边)选择Run图标,快捷键是(Ctrl+Shift+D)

vscode chorem调试 vscode调试功能_多目标_02

运行视图展示了所有运行和调试的信息,还有一个顶部的调试命令和配置设置。

如果运行和调试还没有被配置(没有launch.json被创建),此视图展示运行开始视图。

vscode chorem调试 vscode调试功能_json_03

Run menu(运行菜单)

顶部的运行菜单有大多数常用的运行和调试命令:

vscode chorem调试 vscode调试功能_json_04

Launch configureations(启动配置)

在vscode里面运行和调试一个简单的应用,按下F5,vscode将会尝试去运行你当前激活的文件。

然而,对于大多数调试场景,创建一个启动配置是有益的,因为它运行你配置和保存调试设置细节。vscode保存调试配置信息在launch.json文件中,这个文件存在.vscode目录下,在你的workspace(你的项目根目录),或者你的用户设置,或者workspace设置里。【注:后面还会讲到,应该是个全局的launch.json??】

要创建一个Launch.json,先在vscode中打开你的项目目录(File > Open Folder),然后在运行视图中顶层选择配置齿轮图标。

vscode chorem调试 vscode调试功能_调试器_05

vscode将会尽量自动检测你的调试环境,但是一旦失败,你就需要手动去选择:

vscode chorem调试 vscode调试功能_vscode chorem调试_06

这里是一个启动配置,为Node.js调试生成的:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "program": "${file}"
    }
  ]
}

如果你回去查看File Explorer view (Ctrl+Shift+E),你会发现vscode已经创建了一个.vscode的目录,同时添加了launch.json到你的workspace。

vscode chorem调试 vscode调试功能_json_07

注:你能调试一个简单的应用,即使你没有在vscode里面打开一个目录,但是不可能管理启动配置和设置高级的调试,vsocde的状态栏是“紫色”的如果你没有打开一个目录。

注意,在启动配置中,哪些属性是有效的,在不同的调试器之间是不一样的。你能使用智能提示(Ctrl+Space)找出哪些属性是否存在于一个调试器中。Hover help(悬停帮助)也是有效的,对所有属性。

不要假设一个属性在一个调试器有效就会自动工作于其他调试器。如果你看到绿色的波浪线在你的启动配置文件中,鼠标悬停在上面看看有什么错误,在启动调试会话之前去尽力去解决他们。

vscode chorem调试 vscode调试功能_调试器_08

检查所有自动生成的属性值,确保他们是适用你的项目和调试环境。

启动对比附加配置

在vscode中,有2种核心的调试模式:启动和附加,处理开发者2种不同的工作流和环节。基于不同的工作流,有些配置是否适用于你的项目可能会比较模糊。

如果你是来自于浏览器工具开发者背景的话,你可能会使用“从你的工具启动”,因为你的浏览器已经打开了。当你打开DevTools时,你简单地附加DevTools到你的打开的浏览器tab上 。

另一方面,如果你是来自服务器或者桌面开发背景的话,正常的话,你的编辑器可以为你启动一个进程,然后你的编辑器可以自动为你附近到新启动的进程上。

最好的解释“启动”和“附加”就是考虑“启动”配置就是如何在vscode附近到进程之前是如何启动你的app在调试模式下的;“附加”就是如何连接vscode调试器到你的已经启动的app或者进程。

vscode调试器支持“启动”和“附近”模式调试。依赖于request属性参数(attach or launch),其他不同的属性是必须的,同时launch.json的验证和建议也能有所帮助。

添加一个新的配置

添加新的配置到已经存在的luanch.json,可以使用下面的其中技术:

  • 使用智能提示,当你的鼠标悬浮在配置的数组里。
  • 点击“Add Configuration”按钮去调用片段提示在数组的开始处。
  • 在运行菜单点击“Add Configuration”。

vscode chorem调试 vscode调试功能_多目标_09

vscode还支持组合的启动配置,为同一时间启动多个配置;可以参考:https://code.visualstudio.com/docs/editor/debugging#_compound-launch-configurations

开始一个调试会话的顺序:第一在运行视图中,选择配置下来按钮,选择名称为Launch Program的配置。一旦启动配置已经设置,可以按下F5启动调试会话。

当然,也可以command palette(Ctrl+shift+P)选择“Debug:Select and Start Debugging”,输入‘debug ’,选择你要调试的配置。

一旦调试开始,调试console将显示,将输出调试信息输出,状态栏颜色也变成了“organge”了。

同时,调试状态也显示在状态栏上,展示当前激活的调试配置,通过选择调试状态,用户能改变激活启动配置,开始调试而不需要打开运行视图了。

调试动作

  • Continue / Pause F5
  • Step Over F10
  • Step Into F11
  • Step Out Shift+F11
  • Restart Ctrl+Shift+F5
  • Stop Shift+F5

运行模式

除了调试一个程序,vscode支持运行一个程序。Debug: Run(Start Without Debugging)动作或者Ctrl+F5将使用最近的启动配置运行程序。许多启动配置都支持运行模式。vscode维护着一个调试会话当程序运行时,当按下Stop按钮后,终止程序。

提示:不是所有的调试器都支持运行模式,在这种情况下,运行模式和调试模式时一样的。

断点

断点能被设置通过点击编辑区域或者在当前行按下F9。Finer(更改?)断点(启用/禁用/重新应用)可以在运行视图的BREAKPOINTS区域来完成。

  • 在编辑区域的断点通常显示红色填充圆形。
  • 禁用的断点是填充灰色圆形。
  • 当一个调试会话开始时,不能注册的(生效的)断点会被改成灰色凹陷圆形。同样会发生在如果源代码发生了改变,但是调试会话没有在线编辑(live-edit support)的支持。

"重新应用所有断点"命令设置所有断点到他们原始位置。这是很有用的当调试环境是“懒”和“不对”的断点还没有被执行的时候(???)。

可选的,断点可以显示在编辑器的概览标尺里,通过启用debug.showBreakpointsInOverviewRuler:

vscode chorem调试 vscode调试功能_多目标_10

日志点

一个日志点是一种断点,但是不回中断到调试器的,而是输出一条消息到控制台。日志点是用于注入日志,当调试的产品服务不能被中断和停止时。

一个日志点由一个钻石形状的图标代表。日志消息是一些文本,但是可以包含由大括号('{}')包起来的表达式。

vscode chorem调试 vscode调试功能_调试器_11

就像正常的断点一样,日志点也可以启用,禁用,也能通过条件和设置命中次数来控制。

注:vscode内置的Node.js调试器是支持日志点的,其他调试器也可以实现。比如:Python和Java插件是支持的。

 

数据查看

变量能够被查看,通过运行视图的VARIABLES区域或者鼠标悬浮在编辑器的源码变量上。变量值和表达式值是和在CALL STACK中选中的栈帧有关系的。

vscode chorem调试 vscode调试功能_多目标_12

变量值可以被修改,通过在变量上右键菜单上的Set Value(或者双击也可能可以)。

变量和表达式可以被计算和监视,在运行视图的WATCH区。

vscode chorem调试 vscode调试功能_调试器_13

变量名和值可以被筛选,通过当焦点在VARIABLES区时的输入。

vscode chorem调试 vscode调试功能_vscode chorem调试_14

Launch.json属性

有很多launch.json属性去帮助不同的调试器和调试场景。像上面提到的,你能使用智能提示(Ctrl+Space)去查看一系列有用的属性,一旦你指定了type属性的值。

vscode chorem调试 vscode调试功能_多目标_15

下面的属性是必须的,对每个启动配置:

  • type - 指定调试器,每隔安装的调试插件都有一个类型:node是内置的Node调试器,比如:php和go分别对应PHP和Go插件。
  • request - 启动配置的请求类型,launch 和 attach
  • name - 一个友好的名称,显示在调试启动配置的下拉菜单。

下面这些属性是可选的:

  • presentation - 使用order, group, 和hidden属性在presentation 对象上,你可以排序,分组和隐藏配置和组合在调试配置下拉框和调试快速选择时。
  • perLaunchTask - 去启动一个任务在开始会话之前,设置这个属性为由tasks.json(https://code.visualstudio.com/docs/editor/tasks)(在工作目录的.vscode目录)指定的名称。或者,这个可以设置为${defaultBuildTask}已使用默认的生成任务。
  • postLaunchTask - 去启动一个任务在结束会话之后,设置这个属性为由tasks.json(https://code.visualstudio.com/docs/editor/tasks)(在工作目录的.vscode目录)指定的名称。
  • internalConsoleOptions - 这个控制调试控制台仪表盘的显示,在整个调试会话中。
  • debugServer - 仅仅为调试插件作者,这个属性允许你去连接一个指定的端口去代替启动一个调试适配器。
  • serverReadyAction - 如果你想打开一个url在浏览器中当程序在调试下输出一个指定消息到调试控制台或者集成终端时。详细请参考 Automatically open a URI when debugging a server program.

许多调试器支持下面这些属性:

  • program - 指定运行的执行程序或者文件,当启动调试的时候。
  • args - 传递给程序的参数
  • env - 环境变量(使用null可以"undefine"(未定义)一个变量)
  • cwd - 当前工作目录,用于查找依赖和其他文件
  • port - port当要附加到一个运行程序时
  • stopOnEntry - 是否中断当程序启动时
  • console - 使用哪种控制台,internalConsole, integratedTerminal, 或者externalTerminal

变量替代

vscode将常用的路径和其他有效值作为变量,并且支持变量替代在launch.json内部。这表示你不用使用绝对路径在调试配置里。如果,${workspaceFolder}表示工作区目录,${file}表示在激活编辑中打开的文件,${env:Name}表示名称为'Name'的环境变量值。你可以看到完整的一系列预定义的变量在Variables Reference 或者在launch.json里通过调用智能提示来查看。

{
  "type": "node",
  "request": "launch",
  "name": "Launch Program",
  "program": "${workspaceFolder}/app.js",
  "cwd": "${workspaceFolder}",
  "args": ["${env:USERNAME}"]
}

平台相关属性

launch.json支持定义值(比如:传递给程序的参数)基于不同的操作系统调试时。为支持这个,放置一个平台相关字段在launch.json里,并且 指定相关的属性在这个字段里。

下面时一个传递“args”到程序的例子,Windows系统不一样:

{
  "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在远程调试时间接地决定了平台,并且会导致循环依赖。

下面的例子说明调试时,总是stops on entry,除了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
      }
    }
  ]
}

全局启动配置

vscode支持添加一个“启动”对象在你的用户设置里。这个启动配置将会被共享到所有的工作区。比如:

"launch": {
    "version": "0.2.0",
    "configurations": [{
        "type": "node",
        "request": "launch",
        "name": "Launch Program",
        "program": "${file}"
    }]
}

小提示:如果当前工作区包含了launch.json,那么全局启动配置将会被忽略。

高级断点

条件断点

一个强大的vscode调试特性就是有能力去设置条件,基于表达式,命中次数,或者2者的结合。

  • 表达式条件:无论何时,只要表达式的值为true,断点将会被命中。
  • 命中次数:命中次数控制在中断之前,允许断点多少次被命中。命中次数是否重要和精确语法在不用的调试器中是不一样的。

你可以增加一个条件 and/or命中次数当你创建断点的时候,或者修改一个存在的断点(通过编辑断点)。这2种情况,将会弹出一个带下拉框的输入框,用于输入表达式:

vscode chorem调试 vscode调试功能_vscode chorem调试_16

如果一个调试器不支持条件断点,Add Conditional Breakpoint 操作将会不显示。

 

Inline(内联)断点

内联断点仅仅在执行到达指定列的时候,才会命中。这个通常很有用,当调试缩小代码时,它可能包含了好几条语句在一行里。

一个内联断点可以通过Shift+F9来设置,或者通过右键在调试时。内联断点显示在编辑中。

内联断点也可以有条件,编辑多个断点在一行是可以的,通过在编辑器左边区域右键。

 

函数断点

 相对于直接在源代码里直接放置断点,调试器也能支持通过知道函数名来创建断点。这是很有用的,当源代码可能无效,但是函数名是知道的。

函数断点可以通过在BREAKPOINTS区头部点击+然后输入函数名来创建。函数断点里BREAKPOINTS里面显示为红色三角。

 

数据断点

如果调试器支持数据断点,他们可以在VARIABLES区设置,并且会在变量值改变时命中。数据断点显示红色六边形。

 

调试控制台REPL

表达式可以被计算在Debug Consol REPL。想要打开调试控制台,可以通过顶部菜单,或者VIew:Debug Console(Ctrl+Shift+Y)。表达式在你按下Enter之后,Debug Console REPL会显示建议根据你的输入。如果你需要输入多行,使用Shift+Enter分行,然后输入Enter。调试控制台输入输入当前激活的编辑器的模式,这表明它支持语法颜色,缩进,引号闭合和其他语法特性。

vscode chorem调试 vscode调试功能_多目标_17

注:你必须在调试模式下才能使用Debug Console REPL.

重定向输入/输出 去/来调试目标

重定向输入/输出是调试器/运行时相关的,所以vscode没有一个内置的解决方案用于工作在所有的调试器上。

这里有2个途径你可以考虑:

1. 手动地启动一个程序在终端或者在命令行提示符下,然后根据需要重定向输入/输出。确保传递合适命令行选项给调试目标,以便调试器能附加上去。创建和运行一个“attach”调试配置附加到调试目标上。

2. 如果你的调试插件能够使用vscode集成的集成终端(或者外部终端),你能尝试使用shell重定向语法(">"或者"<")作为参数。

下面是一个例子:

{
  "name": "launch program that reads a file from stdin",
  "type": "node",
  "request": "launch",
  "program": "program.js",
  "console": "integratedTerminal",
  "args": ["<", "in.txt"]
}

这个方法需要"<"语法传递给调试器插件,并且在集成终端不能修改为结束。(???)

多目标调试

对于一些复杂场景引入了过个进程(比如:一个客户端和一个服务端),vscode支持多目标调试。

使用多目标调试很简单:在你启动第一个调试会话之后,你可以在启动另外一个会话。一旦第二个会话启动运行,vscode界面将切换到多目标模式。

每个会话现在在CALL STACK视图里都显示在顶层元素上

vscode chorem调试 vscode调试功能_json_18

调试工具栏显示当前激活的会话(其他会话在下拉菜单中)

vscode chorem调试 vscode调试功能_vscode chorem调试_19

调试动作(比如,所有动作在调试工具栏上的)都将执行在激活的会话中。激活的会话可以被改变,通过调试工具栏的下拉菜单或者在CALL STACK视图里选择一个不同的元素。

组合调试配置

另一个启动多个调试会话的方法是使用组合调试配置。一个组合调试配置可以列出2个或者多个启动配置被同时启动。可选的perLaunchTask可以被指定在每个会话启动之前运行。

{
  "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}"
    }
  ]
}

组合调试配置显示在启动配置的下来菜单中。

远程调试

vscode本身不支持远程调试: 这是一个调试插件可以使用的特性,你可以咨询Marketplace市场插件页,获取支持和细节。

然而有个例外:vscode包含的Node.js调试器支持远程调试,参考这里 Node.js Debugging 去学习如何配置它。

自动打开URIL当调试一个服务程序时

调试一个web程序时,典型的需要打开一个指定的url在浏览器中,为命中服务端代码在调试器中。vscode有一个内置的特征"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”的处理器,然后启动http服务在端口3000上。这个端口显示在调试控制台,然后开发者现在需要输入http://localhost:3000到他们的浏览器中。

这个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属性描述了端口号如何转换成URI。第一个%s被替代成匹配模板中的第一个获取组。

最终的  URI在vscode外部标准的应用配置打开,通过URI的scheme。

 或者,action也可以被设置成debugWithChrome。这样,vscode会启动一个chrome调试会话为URI(这需要Debugger for Chrome插件被安装)。在这种模式下,webRoot属性可以被添加并传给chrome调试会话。

我们简化一个,大多数属性是可选的,我们使用下面fallback values(???):

  • pattern: "listening on.* (https?://\\S+|[0-9]+)" 匹配常用的消息 "listening on port 3000" or "Now listening on: https://localhost:5001".
  • uriFormat: "http://localhost:%s"
  • webRoot: "${workspaceFolder}"

下面是serverReadyAction 特征:

vscode chorem调试 vscode调试功能_json_20

下一步

去学习vscode的Node.js调试支持,看看这里:

  • Node.js - 描述Node.js调试, 包含在vscode里.

去看看Node.js调试基础的教程,可以看看这些视频:

  • Intro Video - Debugging - 展示调试基础.
  • Getting started with Node.js debugging - 显示如何附加调试器到一个正在运行的Node.js进程上.

去学习vscode代码任务运行任务,去:

  • Tasks - Describes how to run tasks with Gulp, Grunt and Jake, and how to show errors and warnings.

去写一个你自己的调试器插件,访问:

  • Debugger Extension - Uses a mock sample to illustrate the steps required to create a VS Code debug extension.

常见问题

支持哪些调试场景?

调试Node.js的应用支持在Linux, mscOS和Windows,开箱即用。其他调试场景的支持通过VS Code extensions插件市场上的插件。

我没有看见任何launch.json子啊运行视图的下拉菜单,哪里错了?

很有可能,你没有设置launch.json,或者有语法错误在那个文件中。或者,你需要打开一个目录,因为没有目录的调试是不支持启动配置的。