ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(有些梦想,纵使永远也没办法实现,纵使光是连说出来都很奢侈。但如果没有说出来温暖自己一下,就无法获得前进的动力。——九把刀)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
一位名叫葛丽丝·霍波(Grace Hopper)的美国海军准将及计算机科学家,同时也是世界最早的一批程序设计师之一。有一天,她在调试设备时出现故障,拆开继电器后,发现有只飞蛾被夹扁在触点中间,从而“卡”住了机器的运行。于是,霍波诙谐的把程序故障统称为“臭虫(BUG)”,把排除程序故障叫DEBUG
Debug是一种程序,一种调试工具,说白了就是供程序员检查修改问题的工具
- 调试是定位软件瑕疵的最直接和最有效的方法 。没有哪个程序员能一下子写出没有错误的代码.而使用以调试器为主的调试工具进行调试是定位瑕疵的最直接方法 , 可以从问题的症状入手, 正向跟踪或者反向追溯。对于大多数瑕疵 , 使用合适的调试方法可 以大大提高定位到问题根源的效率 。今天的软件环境在不断向着大型化 、 并行化、 复杂 化 方向发展 , 定位瑕疵的难度也在随之不断提高。 完全靠读源代码来寻找 b u g 的方法已经很难适应今天的软件发展形势 。 另外 , 枚举和排除法通常也会因系统中的软硬件模块数量太多而难以实施 , 有时候 , 花了几天时间来做替换仍然找不 到怀疑对象
- 调试可以帮助程序员提高编写代码的能力。 因为调试可以让程序员彻底了解程 序的实际执行过程 , 检查与自己设计时的预想是否一致 , 如果不一致 , 那么很可能预示 着有问题存在 , 应该引起重视 。 另外 , 调试过程可以让程序员更好的认识到提高代码可调试性和代码质量的重要性 。 从此 , 自觉的改进编码方式 , 合理添加用来支持调试的代码 。编码和调试是程序员日常工作中的两个最主要任务 , 这两个任务是相辅相成的 , 编写具有可调试性的高质量代码 , 可以明显提高调试效率 , 节约调试时间。 另 一方面 , 调试可以让程序员真切感受程序的实际执行过程 , 反思编码和设计中的问题 , 加深对软件和系统的理解 , 提高对代码的感知力和控制力
- 调试工具是学习计算机系统和其它软硬件知识的好帮手 。通过软件调试技术的强大观察能力和断点、 栈回溯 、 跟踪等功能可以快速的了解一个软件和系统的模块 、 架构 、和工作流程 , 因此是学习其它软硬件技术的一个快速而有效的方法
使用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/
在下面的演示中,使用了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 ~');
});
vscode launch.json变量配置表说明
字段名称 | 字段描述 |
---|---|
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": [
"/**"
],
"program": "${workspaceFolder}/app.js"
}
]
}
然后我们使用该配置文件运行
vscode调试动作
- 继续/暂停F5
- 越过F10
- 进入F11
- 移出Shift + F11
- 重新启动Ctrl + Shift + F5
- 停止Shift + F5
它只是临时将表达式添加在代码中,达到开发者更方便的调试代码的目的
它由菱形”形状的图标表示,且有表达式的断点可以看到有一个双横杠在这里插入图片描述
就像常规断点一样,可以启用或禁用对数点,也可以通过条件和/或命中数进行控制
变量可以在“ 运行”视图的“ 变量”部分中检查,也可以将鼠标悬停在编辑器中的源上进行检查。变量值和表达式评估相对于“ 调用堆栈”部分中的选定堆栈帧
可以使用变量的上下文菜单中的“ 设置值”操作来修改变量值
相比较在代码中调试断点,在控制面板,我们可以更清晰的看到程序执行的堆栈信息
可以使用Debug Console REPL(Read-Eval-Print Loop)功能对表达式求值。要打开调试控制台,请使用“ 调试”窗格顶部的“ 调试控制台”操作,或使用“ 查看:调试控制台”命令(Ctrl + Shift + Y)。按下Enter键后,将对表达式求值,而Debug Console REPL将在您键入时显示建议。如果需要输入多行,请在各行之间使用Shift + Enter,然后使用Enter发送所有行以进行评估。调试控制台输入使用活动编辑器的模式,这意味着调试控制台输入支持语法着色,缩进,自动关闭引号和其他语言功能
详情可以参见官网
https://code.visualstudio.com/docs/nodejs/nodejs-debugging
VS Code具有对TypeScript调试的内置支持。为了支持结合执行中的JavaScript代码调试TypeScript
npm install -g typescript
tsc --version
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
"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
该文件定义了TypeScript 项目设置,例如编译器选项和应包含的文件
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "out"
}
}
- target 指定ECMAScript目标版本
- module 指定模块代码生成类型
- outDir 将输出结构重定向到目录
tsc
更多typescript.json配置请查看官方了解
提供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文件
使用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 app.ts
{
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"outDir": "out"
}
}
{
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/app.ts"
]
}
]
}
egg
https://eggjs.org/zh-cn/intro/index.html
使用egg ts脚手架生成项目
mkdir showcase && cd showcase
npm init egg --type=ts
npm i
npm run dev
{
"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*"
]
}
{
"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
}
]
}
选择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控制面板启动
选择启动的npm脚本