一、debugger 语句调用任何可用的调试功能,例如设置断点。 如果没有调试功能可用,则此语句不起作用。

语法

  1. debugger;

JavaScript如何实现debugger

一、debugger的实现依托于引擎、系统和硬件,计算机操作系统和CPU在设计之初就支持了debugger的能力,不同语言和平台的debugger实现机制不同。想要进一步了解debugger,首先需要知道代码是如何在计算机(机器)上跑起来的。

debugger原理

一、剖析cpu或者操作系统如何实现debugger,涉及到计算机硬件、组成原理以及汇编语言等知识范畴。

编译型语言

中断

一、cpu指令集规定了cpu可以执行什么指令,每种指令需要提供什么样的操作数,不同类型的cpu会有不同的指令集。指令集会按照执行顺序不间断执行,但是程序在运行过程中不免要处理一些外部消息比如网络请求、异常、io读写操作等,所以cpu设计了中断机制,cpu每执行完一条指令就会去看下中断标记,是否需要触发中断机制。

INT指令

一、INT指令是cpu中用来引发中断过程的指令,中断指令有对应的编号,不同的编号对应不同的处理程序,记录编号和中断处理程序的表叫做中断向量表。其中INT3(即3号中断)用来触发debugger。
二、调试器将INT3当做软件中断指令来用,当在可执行文件中的某一位置加断点的时候,调试器会把断点处指令编码的第一个字节替换成INT3指令的编码。当程序执行到INT3,会向调试器申请系统调用权,此时调试器获得cpu控制权,同时也可以获取相应的环境数据来做调试。
三、在需要恢复断点的时候再将被替换掉的指令编码替换回去即可完成。综上,可执行文件的debugger最终依靠的是cpu的中断机制来实现。

解释型语言

一、编译型语言因为最终将会转换为机器码在操作系统上执行,所以要利用cpu和OS的中断机制和系统调用来实现debugger。但是解释型语言有自己的解释器(自己实现代码的解释执行),实现debugger也相对简单一些,不需要cpu的3号中断。
二、解释型语言通过插入一段代码来实现断点,支持环境数据的查看和代码的执行,当释放断点时解释器能够继续往下执行。
三、像js等脚本语言可以通过debugger语句实现断点,但是断住之后如何获取环境数据则需要debugger客户端来实现,常用的debugger客户端有chrome devtools、vscode debugger等等。
四、在chrome devtools中,V8引擎会把设置断点、连接请求、获取环境信息以及执行脚本的能力通过socket暴露出来以提供调试协议,要实现debugger,就要遵循并对接引擎的底层协议。

V8 debug protocol

一、这份协议中列出了实现debug相关的socket信息以及各请求/响应体的参数类型,非常详尽,我们可以根据所需查看一部分协议内容:
设置断点请求:
image.png

  1. {
  2. "seq":117,
  3. "type":"request",
  4. "command":"setbreakpoint",
  5. "arguments": {
  6. "type":"function",
  7. "target":"f"
  8. }
  9. }
  10. {
  11. "seq":118,
  12. "type":"request",
  13. "command":"setbreakpoint",
  14. "arguments": {
  15. "type":"script",
  16. "target":"test.js",
  17. "line":100
  18. }
  19. }

清除断点请求:

{
    "seq":117,
    "type":"request",
    "command":"clearbreakpoint",
    "arguments": {
        "type":"function",
        "breakpoint":1
    }
}
{
    "seq":118,
    "type":"request",
    "command":"clearbreakpoint",
    "arguments": {
        "type":"script",
        "breakpoint":2
    }
}

继续执行代码:
image.png
image.png

{
    "seq":117,
    "type":"request",
    "command":"continue"
}
{
    "seq":117,
    "type":"request",
    "command":"continue",
    "arguments": {
        "stepaction": "next",
        "stepcount": 5
    }
}

通过node调试js代码

一、chrome和nodejs底层都使用了V8引擎,因此除了在chrome devtools上调试js代码之外,也可以直接使用node cli调试。

调试方式

有多种方式可以连接到nodejs inspector服务器(nodejs调试器):

  • node cli
  • devtools

  • node cli

    一、一种是通过node cli,使用 inspect 指令引擎会临时搭建一个websocket服务器用来监听debugging客户端,其调试原理就是遵循了v8的debug protocol。
    image.png

    devtools

    一、另一种方式可以使用chrome提供的专门用来调试nodejs的devtools,前提是需要在devtools中配置好nodejs服务器对应的地址(host)和端口号(port)。
    image.png

此外,对于上一节中提到的v8引擎中的Ignition解释器和TurboFan编译器分别对js代码执行了不同的处理(分别转换为字节码和机器码),也可以通过nodejs指令运行查看。
node --print-bytecode test_demo.js
image.png
node --print-code test_demo.js
image.png