在 Chrome 中调试

在编写更复杂的代码前,让我们先来聊聊调试吧。

所有的现代浏览器和大多数其他环境都支持“调试” —— 开发者工具中的一个特殊的 UI,可以让你更容易地发现和修复错误。

在这里我们将会使用 Chrome(谷歌浏览器),因为在这方面它可能是功能最丰富的。

“sources(资源)” 面板

你的 Chrome 版本可能看起来有一点不同,但是应该还是很明显就能发现的。

  • 在 Chrome 中打开示例页面
  • 使用快捷键 F12 (Mac: Cmd+Opt+I) 打开开发者工具。
  • 选择 sources(资源) 面板。

如果你是第一次这么做,那你应该会看到下面这个样子:

切换按钮 会打开文件列表的选项卡。

让我们在预览树中点击和选择 index.htmlhello.js。应该会出现这个视图:

我们可以看到三个区域:

  1. 资源区域列出了 html、javascript、css 和包括图片在内的页面需要的其他文件。Chrome 扩展的资源也会出现在这。
  2. 源区域展示源码。
  3. 信息和控制区域是用来调试的,我们很快就会来探讨它。

现在你可以再次点击切换按钮 隐藏资源列表来给代码腾出更多的空间。

Console(控制台)

如果我们按下 Esc,下面会出现一个控制台,我们可以输入一些命令然后按下 Enter 来执行。

语句执行之后,会将其结果显示在下面。

例如,1+2 将会返回 3hello("debugger") 函数什么也不返回,因此结果是 undefined

Breakpoints(断点)

我们来看看示例页面发生了什么。在 hello.js 中,点击第 4 行。是的,就点击数字 "4" 上,不是点击代码。

恭喜你!你已经设置了一个断点。现在,请在第 8 行的数字上也点击一下。

看起来应该是这样的(蓝色的是你应该点击的地方):

断点是调试器会自动暂停 JavaScript 执行的地方。

当代码被暂停时,我们可以检查当前的变量、在控制台执行命令等等。换句话说,我们可以调试它。

我们总是可以在右侧的面板中找到断点的列表。当我们在数个文件中有许多断点时,这是非常有用的。

  • 快速跳转至代码中的断点(通过点击右侧面板中的对应的断点)。
  • 通过取消选中来临时禁用。
  • 通过右键单击和选择移除来删除一个断点。
  • 等等。
条件断点

在行号上右键单击允许你创建一个条件断点。只有当给定的条件为真(即满足条件)时才会被触发。

当我们在特定的变量值或参数的情况下需要停止程序执行时,这种调试方法就很有用了。

Debugger 命令

我们也可以使用 debugger 命令来暂停代码,像这样:

function hello(name) {
  let phrase = `Hello, ${name}!`;

  debugger;  // <-- 调试器会在这停止

  say(phrase);
}

当我们在一个代码编辑器中并且不想切换到浏览器在开发者工具中查找脚本来设置断点时,这真的是非常方便啦。

暂停并查看

在我们的例子中,hello() 函数在页面加载期间被调用,因此激活调试器的最简单的方法就是 —— 重新加载页面。因此让我们按下 F5 (Windows, Linux) 或 Cmd+R (Mac) 吧。

设置断点之后,程序会在第 4 行暂停执行:

请打开右侧的信息下拉列表(箭头指示出的地方)。这里允许你查看当前的代码状态:

  1. Watch —— 显示各种表达式的当前值。

    你可以点击加号 + 然后输入一个表达式。调试器将随时显示它的值,并在执行过程中自动重新计算。

  2. Call Stack(调用栈) —— 显示嵌套的调用链。

    此时,调试器正在 hello() 的调用链中,被 index.html 中的一个脚本调用(这里没有函数,因此显示 “anonymous”)

    如果你点击了一个堆栈项,调试器将调到相应的代码那,并且还可以查看其所有的变量。

  3. Scope(作用域) —— 显示当前的变量。

    Local 显示当前函数中的变量,你还可以在源代码中看到它们的值高亮显示了出来。

    Global 显示全局变量(不在任何函数中)。

    还有一个 this 关键字目前我们还没有学到,不过我们很快就会讨论它了。

跟踪执行

现在是跟踪脚本的时候了。

在右侧面板的顶部有一些按钮。让我们来使用它们吧。

—— 继续执行,快捷键 F8.

继续执行。如果没有其他另外的断点,那么程序就会继续执行,并且调试器不会再控制程序。

如果我们点击一下之后我们会看到这样的情况:

执行器已经继续了,到了 say() 函数中的另外一个断点然后暂停在那里。看一下右边的 “Call stack(调用栈)”。它已经增加了一个调用信息。我们现在在 say() 里面。

—— 下一步(运行下一个命令),但是不会进入函数,快捷键 F10

如果我们现在点击它,alert 会被显示出来。注意这里 alert 可以是任何函数,执行器会 “跨过(step over)”,跳过函数的内部。

—— 下一步,快捷键 F11

和前一个一样,但是 “跨进(step into)” 嵌套的函数。单击此操作将一步一步地执行所有脚本操作。

—— 继续执行到当前函数的末尾。快捷键 Shift+F11

执行器将会停止在当前函数的最后一行。当我们使用 偶然的进入到一个嵌套调用但是对我们并没有什么用,我们想要尽可能的继续执行到最后的时候是非常方便的。

—— 启用/禁用所有的断点

这个按钮不会影响程序的执行。只是一个对批量断点的开/关。

—— 发生错误时启用/禁用自动暂停。

当启动自动暂停功能并且开发者工具是打开着的时候,当脚本错误时会自动暂停执行。然后我们可以分析变量来看一下什么出错了。因此如果我们的脚本因为错误挂掉的时候,我们可以打开调试器,启用这个选项然后重载页面,查看一下哪里导致它挂掉了和当时的上下文是什么。

继续到这

在代码中的某一行上右键打开一个带有 “Continue to here(继续到这)” 的非常有用的选项的菜单。

当你想要向前移动很多步但是又懒得设置一个断点时非常的方便。

日志记录

想要输出一些东西到控制台上?有一个 console.log 可以满足你。

例如:将从 04的值输出到控制台上:

// 打开控制台来查看
for (let i = 0; i < 5; i++) {
  console.log("value", i);
}

普通用户看不到这个输出,它是在控制台里面的。要想看到它 —— 或者打开开发者工具中的 Console(控制台)选项卡,或者在一个其他的选项卡中按下 Esc:这会在下面打开一个控制台。

如果我们在代码中有足够的日志记录,那么我们可以从记录中看到刚刚发生了什么,而不需要借助调试器。

总结

我们可以看到,有 3 种方式来暂停一个脚本:

  1. 一个断点。
  2. debugger 声明。
  3. 一个错误(如果开发者工具是打开状态并且按钮 是开启状态)。

然后我们就能检查变量,并逐步查看执行器在哪里走错路了。

开发者工具中还有比这篇文章中更多的选项。完整的手册在 https://developers.google.com/web/tools/chrome-devtools

本章节中的信息足够开始调试了,但是以后,尤其是你做了大量关于浏览器的东西后,请你去(上面的链接里)查看开发者工具的更高级功能。

对了,你也可以点击开发者工具中的其他地方来看一下会显示什么。这可能是你学习开发者工具的最快的路线了。不要忘了还有右键单击哟。

教程路线图

评论

在评论之前先阅读本内容…
  • 欢迎你在文章下添加补充内容、提出你的问题或回答提出的问题。
  • 使用 <code> 标签插入几行代码,对于多行代码 — 可以使用 <pre>,对于超过十行的代码 — 建议使用沙箱(plnkrJSBincodepen 等)。
  • 如果你无法理解文章中的内容 — 请详细说明。