前端断点调试是如何实现的?

轻松掌控前端错误:浏览器断点调试的实用技巧 无论是跟踪JavaScript错误还是优化页面性能,掌握浏览器的断点调试技巧都能让你轻松解决开发中的难题,本文将带你深入探索这些技巧,让你从头痛的调试过程转变为得心应手的开发体验。 阅读详情
AI摘要

本文从抖音开发者工具断点调试需求出发,介绍前端调试方式。阐述 Chrome Devtools Protocol 概念、常见信息及应用场景,深入分析浏览器、Vscode Web 代码和 IDE 小程序断点调试原理,包括操作流程、通信源码等,助读者掌握前端调试基本原理。

抖音小程序开发者工具(https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/developer-instrument/overview)是面向字节系小程序开发者推出的桌面端集成开发环境,支持小程序开发、调试、预览、上传等基本功能,旨在帮助开发者更高效地开发小程序,我也是负责本地开发能力的建设。

因为工作原因最近对断点调试进行一些研究,百度了一下,遗憾的是发现网络上大部分内容都是在教学如何使用调试工具,并没有扩展到具体的细节,譬如通信逻辑,基本原理等。因此,为了尝试去弄懂一些断点调试的底层逻辑,特意去找了一些英文文档并实践。

前言

作为一个前端开发,前端调试的方式一般有如下几种:

  1. 代码中直接打印,比如很多时候直接在代码中使用 console 来打印一些变量,或者在 vscode 中使用 Turbo Console Log 等插件生成特色的日志内容。

    图片

  2. debugger,在代码中输入 debugger 关键字,然后在浏览器中进行断点调试,或者在浏览器中找到源码,然后进行断点调试。

    图片

  3. vscode 自带的 web 调试能力。

    图片

相比于 console,debugger 可以看到代码实际的执行路线以及每个变量的变化,代码可以跳着看,也可以针对某个函数步步执行。

但是 console 与 debugger 方式对代码都有侵入,在开发阶段可能要不断增加和移除来调试,如果不小心忘了,那 mr 又得打回并重新提交了…

🧐 相信很多人在提 mr 都有类似经验…

相对来说,浏览器中找到 source 源码打断点是一个更好的方式,但是还是需要打开 Devtools ,并在 sources 面板找到文件注入断点,操作上也是有点小麻烦。

因此第 3 种方式,可能是不错的方式,在 vscode 中直接在源码中调试,并能看到具体的变量信息和网页效果。

实际上,浏览器打断点与在 vscode 打断点本质原理都类似。下面就聊一聊浏览器断点调试和 vscode 断点调试的原理。

基本知识

Chrome Devtools Protocol

在了解具体场景之前,首先有一个比较重要的概念,那就是 CDP。

基本概念

CDP(Chrome DevTools Protocol)是一种通过网络协议与 Google Chrome 或其他兼容的浏览器进行通信的协议。通过 CDP,开发者可以远程控制浏览器,获取浏览器状态信息,以及执行各种浏览器操作,从而实现自动化测试、性能分析、调试等应用场景。

🥶📚:

CDP 最早于 2011 年在 Chrome 15 版本中引入,作为 Chrome DevTools 的核心组件之一而出现。在此之前,开发者通常需要通过浏览器插件或者第三方工具来进行调试和测试,这些工具通常不够标准化和通用,也难以实现远程控制。

就跟 Emoji 的历史差不多了,都是乱的,然后规范化,最后大力发展。

CDP 的出现解决了这些问题,使得开发者可以通过标准化的协议来远程控制浏览器,获取浏览器状态信息,以及执行各种浏览器操作。CDP 的出现和发展推动了 Web 开发和测试的发展,为开发者带来了更加高效和便捷的开发和测试方式。

CDP 通过 JSON-RPC 协议来进行通信,提供了一套完整的 API,包括 DOM、CSS、网络、调试、安全等方面的接口。实际上,可以使用各种编程语言来编写 CDP 客户端,从而实现与浏览器的交互。

图片

上图为 CDP 的官网(https://chromedevtools.github.io/devtools-protocol),可以看到,CDP 包括很多 Domains,常见的 CDP 信息包括:

  • DOM:提供了对文档对象模型的访问和操作接口,如节点遍历、样式计算、事件处理等。

  • CSS:提供了对样式表的访问和操作接口,如样式计算、应用、修改等。

  • Network:提供了对网络请求和响应的访问和操作接口,如请求拦截、修改、模拟等。

  • Console:提供了对浏览器控制台的访问和操作接口,如日志记录、错误捕获、命令执行等。

  • Debugger:提供了对浏览器调试器的访问和操作接口,如断点设置、单步执行、变量查看等。

  • Performance:提供了对浏览器性能分析的访问和操作接口,如性能指标获取、性能分析报告生成等。

这几个也是平常开发中最常用到的几个 Domains 了。

常见 CDP

  • Page:Page.navigate:页面跳转

  • Network:Network.enable:开启网络,可以用来模拟网络开闭能力

  • DOM:DOM.getDocument:获取页面树,比如调试器 Elements 面板的展示

  • CSS:CSS.getComputedStyleForNode:返回给定 nodeId 的所有样式,比如点击 dom 节点,展示 css

  • Runtime:Runtime.evaluate:在当前页面中执行 JavaScript 代码

  • Debugger:下面会提到很多,譬如 Debugger.pause/Debugger.setXXX

应用场景

chrome 的 Devtools (Front-End Devtools)与 Web Page 之间的调试也是通过 CDP 通信的,如下图所示:

图片

除了调试,CDP 额外应用场景也很多,比如刚才提到的自动化测试,通过 CDP 模拟用户行为,操作页面元素等,或者 CDP 获取浏览器的性能指标生成性能报告,还可以通过 CDP 模拟浏览器行为,获取页面数据,实现爬虫等等。

浏览器断点调试原理

带着问题出发,可能需要搞懂以下 3 点:

  1. 页面与 Devtools 是如何通信的?

  2. 断点操作逻辑通信过程是什么?

  3. 如何实现命中断点并停止代码执行的?

操作流程

增加断点

在浏览器中,网页的调试能力是由 Devtools 提供的。Devtools 与网页之间的通信利用的是 Websocket,而通信协议则是 CDP。

除了开发中常用到的元素高亮,日志打印和网络审查,上面也提到了还可以在 sources 面板中使用 debugger。

如下图所示,找到一行 js 代码,在代码中点击断点调试,可以看到 Protocol Monitor 中有一些 CDP 消息,下面就来具体分析一下相关 CDP 信息。

图片

为什么会发送多次,我也不理解,内容基本上是一致的。

点击断点以后,主要有以下一些 CDP 消息在页面与 Devtools 之间通信:

  • Debugger.setBreakpointsActive:Activates / deactivates all breakpoints on the page.

  • Debugger.setBreakpointByUrl:Sets JavaScript breakpoint at given location specified either by URL or URL regex.

  • Debugger.getPossibleBreakpoints:Returns possible locations for breakpoint.

setBreakpointsActive 表示告诉页面要设置一个调试断点了;setBreakpointByUrl 则是告诉页面设置的具体信息;getPossibleBreakpoints 表示设置以后获取正确的断点位置,并展示蓝色小块。

有时候可能会发现设置了某一行为断点,但是断点的位置并不是指向的位置,而是另外的位置。比如上面截图,如果在 15 行设置断点,则最后展示断点位置为 18 行。

图片

图片

整体流程如下图:

图片

移除断点

除了在 sources 面板增加断点,还可以取消断点。取消断点的 CDP 非常简单, Devtools 会给 Web Page 发送一个 Debugger.removeBreakpoint 来移除断点。

图片

实时断点调试

当点击完断点以后,页面会走到断点所在的代码位置,同时 Devtools 会接收到一些 CDP 消息,通知它当前断点的状态和上下文信息。

我写了一个实例,是关于数字的增减逻辑,并在数字增加的时候,走到断点位置(不需要刷新页面)。

图片

可以看到,当点击 + 号以后,页面就进入断点调试逻辑,此时 Devtools 会收到 Debugger.paused消息:

  • Debugger.paused:Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria.

此时表示页面已经暂停了代码执行,Devtools 可以通过 Debugger.paused事件中的参数,获取当前断点的上下文信息,如断点所在的函数、变量值、堆栈信息等。

图片

具体信息没有对应看

图片

点击“Step Over next function call”(按钮 1),Devtools 会收到 Debugger.resumed rɪˈzuːm d 消息,通知继续执行代码。

  • Debugger.resumed:Fired when the virtual machine resumed execution.

随后代码跳到下一行,此时又会收到 Debugger.paused消息。

点击“Resume Script Execution” (按钮 2)按钮,Devtools 会收到 Debugger.resumed消息,如果还存在断点,则此时也会收到 Debugger.paused消息。

此外这里还有一个 Overlay.setPausedInDebuggerMessage 消息,为 Devtools 发送给页面,其信息主要是让页面展示代码停止状态下应该展示的消息,默认为 {"message":"Paused in debugger"},也就是如下图展示的内容:

图片

除了上面两个按钮,还有几个调试按钮,如下图绿色区域内:

图片

分别是:Step into next function call、Step out of current function、Step、Deactivate breakpoints。

🥶📚:

  • Step into next function call:这个按钮用于进入当前行代码所在的函数内部,即单步进入函数中执行。

  • Step out of current function:这个按钮用于跳出当前函数,即单步跳出当前函数执行。

  • Step:这个按钮用于单步执行代码,即逐行执行代码。

  • Deactivate breakpoints:这个按钮用于禁用所有的断点,即暂停调试器的所有断点。

点击“Step into next function call”,Devtools 会发送 Debugger.stepInto 消息,并收到 Debugger.resumed和 Debugger.paused消息,进入到函数内部。

  • Debugger.stepInto:Steps into the function call.

图片

点击“Step out of current function”,Devtools 会发送 Debugger.stepOut消息,并收到 Debugger.resumed和 Debugger.paused消息,跳出该函数。

图片

点击 “Step” 按钮,Devtools 则发送 Debugger.stepInto,代码执行到下一行,每次点击,都会发送 Debugger.stepInto消息。

点击 “Deactivate (/ˌdiˈæk.tɪ.veɪt/) breakpoints”,Devtools 则发送 Debugger.setBreakpointsActive 消息。如果当前断点状态为执行状态,则参数为 active: false,同时设置蓝色小块颜色为透明色。

图片

重新执行代码,断点调试能力失效。

再点击一次,则参数为 active: true,断点调试能力生效。

基本通信源码

了解完相关断点操作流程以后,再分析一下相关逻辑的源码。

首先,Devtools 的源码就是 Front-End Devtools,UI 上的逻辑这里就不多分析。关于页面的调试通信逻辑在 DebuggerModel 中:https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/devtools-frontend/src/front_end/core/sdk/DebuggerModel.js;l=280;drc=f09c12c84b39d13189a7039a05253ca3766d4751;bpv=0;bpt=0

 async stepInto() {
    const skipList = await this.computeAutoStepSkipList("StepInto" /* StepInto  /);  void this.agent.invoke_stepInto({ breakOnAsyncCall: false, skipList });  }  async stepOver() {   this.#autoSteppingContext = this.#debuggerPausedDetailsInternal?.callFrames[0]?.functionLocation() ?? null;  const skipList = await this.computeAutoStepSkipList("StepOver" /  StepOver  /);  void this.agent.invoke_stepOver({ skipList });  }  async stepOut() {   const skipList = await this.computeAutoStepSkipList("StepOut" /  StepOut */);
    if (skipList.length !== 0) {
      void this.agent.invoke_stepOver({ skipList });
    } else {
      void this.agent.invoke_stepOut();
    }
  }
  pause() {
    this.#isPausingInternal = true;
    this.skipAllPauses(false);
    void this.agent.invoke_pause();
  }

很清晰的看到,上面提到的各种操作逻辑的函数,譬如 pause、stepXXX等 API。

这里列举几个操作按钮通信较多的 API。

pause() 的主要逻辑为 2 点:

  1. 设置使页面断点暂停状态为 ture。

  2. 发送 Debugger.paused消息到页面。

stepInto() 的主要逻辑为:

  1. 拿到跳转的 skipList,它是一个字符串数组,用于指定要跳过的函数名称列。在操作调试按钮时,一般都是空数组。

  2. 发送 Debugger.stepInto消息到页面。

其他 API 逻辑类似。

再分析一下 chromium /ˈkroʊ.mi.əm/ 中的断点调试代码逻辑。chromium 中发送 CDP 消息到 Devtools 的逻辑在 devtools_agent_host_impl中,而断点调试逻辑在devtools_session文件中,通过 agent 的 DispatchProtocolMessage最后调用到 session 的 shoulSendOnIO函数。

具体来说,这个函数接收一个包含 CDP 方法的 span 参数,然后检查该方法是否属于一组特定的方法,如果是,则返回 true,表示该 CDP 消息需要转发。

DevToolsSession 是 Chromium 源码中的一个类,代表一个 DevTools 会话。DevToolsSession 负责管理与 DevTools 和页面之间的通信,包括上面提到的调试。

bool ShouldSendOnIO(crdtp::span<uint8_t> method) {
  static auto* kEntries = new std::vector<crdtp::span<uint8_t>>{
      crdtp::SpanFrom("Debugger.getPossibleBreakpoints"),
      crdtp::SpanFrom("Debugger.getScriptSource"),
      crdtp::SpanFrom("Debugger.getStackTrace"),
      crdtp::SpanFrom("Debugger.pause"),
      crdtp::SpanFrom("Debugger.removeBreakpoint"),
      crdtp::SpanFrom("Debugger.resume"),
      crdtp::SpanFrom("Debugger.setBreakpoint"),
      crdtp::SpanFrom("Debugger.setBreakpointByUrl"),
      crdtp::SpanFrom("Debugger.setBreakpointsActive"),
      crdtp::SpanFrom("Emulation.setScriptExecutionDisabled"),
      crdtp::SpanFrom("Page.crash"),
      crdtp::SpanFrom("Performance.getMetrics"),
      crdtp::SpanFrom("Runtime.terminateExecution"),
  };
  ...
}

可以看到,这里定义了所有发送到 Devtools 的 API。在 chromium 的各种断点调试方法,最后都会调用 DispatchToAgent方法,并走到 ShouldSendOnIO逻辑。

命中断点

通过上面的分析,了解到了调试器和页面之间的 CDP 通信内容和 API 的基本实现。那 chromium 又是如何停止代码到断点的呢?为何可以停止代码执行呢?

在 DevTools 中,停止代码执行到断点的核心实现是通过使用 V8 JS 引擎中的断点机制来实现的。当 chromium 执行到一个断点时,V8 会暂停 JS 代码的执行,并将控制权转交给 Devtools。这时候,Devtools 可以执行上述提到的断点调试的各种操作。

这块逻辑的代码在 chromium auction_v8_devtools_agent 和 auction_v8_devtools_session 中,看起来比较复杂,涉及到 AuctionV8DevToolsSession 和 AuctionV8DevToolsAgent 两个类,我的理解是 DevtoolsAgent 提供了一些 Devtools debugger 的服务,并找到对应的 DevtoolsSession 进行通信。V8 将 ws 格式信息转交给了 DevtoolsSession,最后通过 DevtoolsAgent 发送到了 Devtools。

大概逻辑如下:

图片

通过 Devtools Agent,负责接收 Devtools 通信信息,并将断点信息移交给 V8,然后由 V8 来对代码进行停止操作。

V8 里面的逻辑我只能看一个大概,整体逻辑如下:

图片

V8Debugger 是一个抽象,V8DebuggerAgentImpl 类实现了这个类,它是 Debug 类和 V8 调试协议之间的中介,负责将调试消息转换为 V8 调试协议中定义的格式。

关于 V8 断点 Debugger 更底层的逻辑是与 os、cpu 相关,os 提供了系统调用来实现可执行代码的中断。

中断则是 cpu 执行下一条指令之前,关注一下中断标记,从而判断是否需要中断执行。整体逻辑上对照着 Vue 的渲染原理即可,每次事件循环结束后最后去走一次渲染 DOM。

V8 本身也是将 JS 转为可执行语言,这也就是为何 JS 可以在浏览器中拥有断点能力了。

这里涉及到一些指令操作,没有深究。

同时,V8 中断代码执行,也会提供一些环境数据到 Devtools,譬如当前变量数值等,这时候 V8 就会将这些调试信息通过 V8 Debug Protocol 协议的格式丢给 Debug,最后丢给 Devtools,从而鼠标悬浮在 sources panel 即可看到对应的数据内容。

Debugger.evaluateOnCallFrame 和 Runtime.getProperties 可以拿到一些环境信息,前者比如一些 number 数字就可以得到。

图片

Vscode Web 代码断点调试原理

在 Vscode 中调试代码,能让开发者专注于代码本身,一边开发运行一边断点调试查看变量信息,并减少一些脏代码的开发。如下图所示,可以看到,似乎是将浏览器的 Debugger 的逻辑照搬到了 Vscode 中。

图片

在介绍完浏览器断点调试的逻辑以后,我们大概了解了页面与 Devtools 的通信过程和相关 CDP 信息。有了这些基础,我们再分析分析 Vscode 中是如何实现断点调试 Web 代码的。

launch.json

在 Vscode 中配置调试后,会生成一个 .vscode/launch.json 文件,其主要是配置需要调试的 url 和远程调试的端口号 port。

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "针对 localhost 启动 Chrome",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}"
    }
  ]
}

Debugging Architecture of VS Code

[ˈɑrkɪˌtektʃər]

Vscode 并不只是前端开发者调试 JS 使用,还可以调试其他语言,Python 一些教程就建议使用 Vscode 调试。因此 Vscode 的调试架构高度灵活,可以支持多种编程语言和调试场景,并且可以基于该架构实现各种调试扩展。

图片

如上图,Vscode 的调试架构中,有 3 个 Core Module:

  • Debug Adapter:调试适配器是 Vscode 和具体调试目标之间的桥梁。适配器主要就是负责将调试请求转换为调试目标,并将调试目标转为调试器需要的结果,其通过 Vscode Debug Protocol 协议通信。Debug Adapter 提供了一组标准的调试接口,包括设置断点、单步执行、查看变量值等。

  • Debug Extension:调试扩展是 Vscode 内置的插件,提供特定语言或者场景的实现。比如可以调试 JS TS Python 等,同时社区也可以提供相关扩展,譬如 Java:

    图片

  • Debug UI:即 Vscode 的操作界面,它提供了调试器的各种操作和功能,例如设置断点、单步调试、查看变量值等。

🥶📚:别忘了另外一个 Debugger,即为 launch.json 中的 type,指底层的调试目标,例如 Node.js 运行时、Chrome 浏览器等等。比如断点后的信息需要传递给 chrome,需要去暂定代码执行,并断点逐步执行等。

原理

在了解原理之前,先看一些现象:

  1. 当 Vscode 启动调试并走到指定断点时,Chrome 自身调试器也会走到对应的调试逻辑(Devtools 本身也是一个 ws client,任何 client 都会收到 chrome 的 cdp 消息)。

    图片

    图片

  2. 当在 Vscode 调试面板操作 StepInto 按钮时,Vscode 代码会走到下一步,同时 chrome 调试也会走到下一步。

  3. 当在 Chrome Devtools 中操作 StepInto 按钮时,Chrome Devtools 代码也会走到下一步,同时 Vscode 中代码也会跳转到下一步。

通过上面 3 种现象可以看出,Vscode Webpage Devtools 关系如下:

图片

细品一下,这时候就可以知道为何需要 Debug Adapter 了。实际上,就是将 CDP 消息转为 DAP。

Workflow

Vscode Chrome Debug 的工作流程如下:

  1. Vscode 启动 JavaScript 调试器,并配置调试器相关的参数,例如调试类型、调试目标等等。

  2. JavaScript Debug Extension 会根据配置启动一个 Debug Adapter 进程,并向该进程发送调试请求,请求 Debug Adapter 与 Debugger 之间建立连接。

  3. Debug Adapter 进程会根据用户的配置,启动相应的 Chrome,并与对应网页(Debugger)建立连接。

  4. Debug Adapter 进程会将调试结果转换为 Vscode 支持的调试消息格式,即上面提到的 DAP,并将调试消息发送给 Vscode。

这里的核心就是 Extension,其作用就是调度与控制,比如启动 Adapter 进程,发送与接收调试信息等等,属于大 BOSS,而 Adapter 只是下属。

JS Debug Extension

上面提到,chromium 内部是使用 CDP 协议通信,因此 Extension 想要正确调试 Chrome WebPage,首先就得遵守 Chrome 的玩法。比如,在 Vscode 中点击 StepInto 按钮,这时候会将对应操作信息转化为 CDP 信息,然后再发送给 WebPage。

Extension 启动 Chrome 的逻辑在 companionBrowserLaunch 中:https://github.com/microsoft/vscode-js-debug/blob/main/src/ui/companionBrowserLaunch.ts#L50

await vscode.commands.executeCommand('js-debug-companion.launchAndAttach', {
  proxyUri: tunnel ? 127.0.0.1:${tunnel.localAddress.port} : 127.0.0.1:${args.serverPort},
  wslInfo: process.env.WSL_DISTRO_NAME && {
    execPath: process.execPath,
    distro: process.env.WSL_DISTRO_NAME,
    user: process.env.USER,
  },
  ...args,
});

另外,Devtools 与 WebPage 是通过 ws 通信的,这里 JavaScript Extension 内部实现与开发者工具调试器和模拟器的通信相似, Extension 与 WebPage 通信也是拿到了页面的 debug ws url,在 Extension 内部创建一个 ws client,通过该 client 监听来自于 WebPage CDP 信息,并转发到会话的 Adapter,最后再交给 Vscode。

图片

图片

看最新的代码,JS Debug Extension 也会负责部分调试 UI 相关逻辑。

Command 实例

以 StepInto举例,在 Vscode 中点击该按钮以后,会发送一个 DAP 消息:

{
    "command": "stepInTo",
    "seq": number,
    "type": "request",
    "arguments": {
        "threadId": number
    }
}

然后,Exetension 将该消息转为 CDP 消息,并发送给 WebPage:

{
    "id": 1,
    "method": "Debugger.stepInto",
    "params": {
        "callFrameId": number/string
    }
}

WebPage 收到该消息后,返回执行结果到 Extension:

{
    "id": 1,
    "result": {}
}

Extension 再将该 response 通过 Debug Adapter 转给 Vscode,Vscode 调整 UI:

{
  "body": {
      "reason": "OK",
      "threadId": number
  },
  "type": "response"
}

相关 DAP 格式可以在 debug-adapter-protocol 查阅:https://microsoft.github.io/debug-adapter-protocol/overview

如果要在 Vscode 中查看实时的 DAP 和 CDP 消息,可以通过如下操作:

图片

源码调试

上面给到的例子非常简单,js 代码也没有经过构建生成编译后的代码。但是实际场景中开发的项目会引入各种开源库,然后经过诸如 Webpack 等打包构建工具做编译打包,才能在浏览器中运行。编译压缩后的代码一般不具备可读性,因此在编译后代码进行调试成本比较高。

We all know,SourceMap 存储着源码和生产代码之间的映射关系。譬如我这里启动了一个 Vite 项目:

图片

当我在源码的 main.ts 中设置断点时,可以看到 Request 中的 url 为 host:port/src/main.ts,即实际传给 WebPage 的断点文件为编译后的文件。

图片

图片

JS Debug Extension 亦是如此。

当在 Vscode 的源码中增加了一个断点,JS Debug Extension 会根据 sourceMap 将源代码路径映射到编译后的代码路径中,并将这个信息发送给浏览器。

图片

所以呀,解析是前端行为。

扩展:SourceMap 加载

SourceMap 虽然也是静态资源,但是其加载在 Network 面板并不能看到,而是在 Developer Resources 中。

图片

为了启动快,我用的 Vite 来生成项目。Vite 利用了浏览器原生的 ES modules 功能,根据文件依赖关系,生成依赖树,然后各模块文件模块单独加载。Vite 文件都有单独的 SourceMap,不需要配 SourceMap 依赖。

可以看到,这里 Vite 默认是直接内嵌的 SourceMap,无需单独请求, 可以在代码文件加载完成后,就直接解析了,红框里面展示的链接就是 Base64 的形式了。

⚠️SourceMap 的解析是交给 Devtools 本身的,Debugger 只负责运行和暂停。因此,如果断点在 SourceMap 解析完成之前触发,则没法告诉 Debugger 正确的地址,可能会出现断点无效情况。

IDE 小程序断点调试

Devtools Debug

根据上面的介绍,小程序断点调试的最简单办法就是在代码中写上 debugger,然后交给 v8 处理即可。另外还有一种方式就是打开小程序调试器,在 sources panel 中打断点,如下图:

图片

打断点,刷新小程序,即可跳转到断点位置。此时可以看到对应的 CDP 消息中的 Request。

图片

可以看到,这里点击的是 56 行,但实际上 Request 中却不是,Devtools 通过 sourceMap 进行了处理,定位到了 64 行。根据上面提到的源码调试逻辑,这里的位置为编译后的代码位置,找到编译产物代码 app.js 即可看到 real position。

图片

IDE Editor Debug???

考虑到上面提到的 Vscode 有 web 断点调试能力,那 IDE Editor 或许也是可以支持断点调试能力的。

Vscode 可以直接在编辑器运行项目,然后启动自定义的调试目标(Debugger)。

IDE 为小程序运行时的载体,与 Vscode 启动 web 项目不一样,其逻辑为编译完成后生成一个编译产物目录,通过静态服务,Simulator 直接加载对应编译产物。因此,IDE 的 Editor 实际上跟 Simulator 没什么联系的。

假设借用 Devtools Debug 的逻辑,当在 Editor 打断点时,捕获所有的断点 DAP 消息,当开启调试时,刷新模拟器,将所有的断点信息转为 CDP 信息发送给模拟器,或许就可以简单实现该能力。

图片

当然,考虑到是在源码中打断点,这里的难点应该是在于要实现 sourceMap 解析,而 Debug UI 则可以利用 Vscode JS Extension,或者通过自定义实现一个 Debug UI。

总结

本文从抖音开发者工具支持断点调试能力需求引入,概述了浏览器断点调试的基本原理,也介绍了 Vscode Web 代码断点调试能力,详细介绍了各模块中各 CDP 消息通信逻辑。阅读本文可以掌握前端各种调试方法的基本原理。

参考文档

[1]V8 本地调试: https://zhuanlan.zhihu.com/p/568432229

[2]Debugging over the V8 Inspector Protocol: https://v8.dev/docs/inspector

[3]Adapter Debug Protocol: https://microsoft.github.io/debug-adapter-protocol/

[4]SourceMap: https://zhuanlan.zhihu.com/p/615279891

调试艺术:Chrome DevTools 高级断点实战手册 本文深入探讨了Chrome DevTools中高级断点的实战应用,旨在提升前端调试效率与精准度。重点介绍了条件断点、日志点、DOM断点、事件监听器断点、XHR/Fetch断点及异常断点的核心价值与设置方法,帮助开发者从被动排错转向主动狙击,掌握调试的艺术,让复杂问题无处遁形。 阅读详情

相关推荐

本地部署静态网站托管平台 Netlify 并实现外部访问(Windows 版本)

Netlify 是一款基于云计算的网站部署和托管平台,专为开发者提供便捷的静态网站和 Jamstack 应用部署服务。它的能力在于将网站构建、部署、托管以及持续集成等流程高度集成,简化了开发和运维的复杂程度。用户无需关心服务器的配置、维护等工作。本文将详细介绍如何在本地安装 Netlify 以及结合路由侠内网穿透实现外网访问 Netlify。

lyxnwct的博客 523

前端程序调试打断点的方式

1. 普通断点 第一步:在想要断住的那一行,写个dubugger或者双击左侧的行出现红色断点 第二步:打开浏览器,F12打开控制台,刷新浏览器(一定要先打开控制台,不然刷新断点也出不来!) 第三步:下一步,执行代码 查看变量当前值: 结束断点: 想看程序的执行步骤、查找问题都非常方便 2. 条件断点 ...

m0_45382009的博客 1万+

【STM32项目】老人健康跌倒检测系统实现(附教程PCB资料)

功能概述 跌倒检测 倾倒告警,人体角度倾斜至阈值触发蜂鸣报警 异常运动,加速度超过正常行动阈值时触发报警 心率监测 实时检测心率数据 血氧监测 实时检测采集血氧 血压测量 血压在线测量 红外体温 非接触体温采集方案 接触式体温采集方案 实时定位 中科微GPSGT-U12双频GPS北斗 GLONASS IRNSS定位系统 NEMA数据解析 可扩展高精度定位方案厘米级 屏幕显示 数据采集显示 告警阈值设置 语音提示 1欢迎使用老人智慧监测系统

洋洋的博客 1万+

直接在vscode中对前端代码打断点

前端项目在vscode中直接打断点如何生效

miin_ying的博客 2177

利用docx4j与docx4j-ImportXHTML高效实现HTML到Word的自动化转换

本文详细介绍了如何利用docx4j与docx4j-ImportXHTML库,在Java环境中高效实现HTML到Word文档的自动化转换。内容涵盖从环境搭建、核心依赖配置,到集成Spring Boot REST API的完整实战流程,并深入解析了处理图片、CSS样式、字体设置以及使用模板保证样式统一等高级技巧与常见问题解决方案,帮助开发者构建稳定的文档自动化生成流水线。

cnn8visionary的博客 365

STM32CubeMX实战:FreeRTOS内存管理5种方案全解析(附heap_4避坑指南)

本文深入解析了STM32CubeMX环境下FreeRTOS的5种内存管理方案(heap_1到heap_5),重点介绍了heap_4的优化策略与避坑指南。通过对比分析各方案的特点、性能指标及适用场景,帮助开发者根据项目需求选择最优内存管理策略,提升嵌入式系统开发效率与稳定性。

aa123的博客 618

配置VS Code 使其支持vue项目断点调试

起因每个应用,不论大小,都需要理解程序是如何运行失败的。当我们写的程序没有按照自己写的逻辑走的时候,我们就会逐步一一排查问题。在平常开发过程中我们可能会借助来排查,但是现在我们可以借助VS Code断点来调试项目。在可以从 Chrome 浏览器调试你的 Vue 组件之前,你需要更新 webpack 配置以构建 source map。做了这件事之后,我们的浏览器就有机会将一个被压缩的文件中的代码对应回其源文件相应的位置。

gqk01的博客 1万+

炼丹-Pyecharts: JupyterLab无法render_notebook

炼丹-Pyecharts: JupyterLab无法render_notebook问题描述Jupyter-Lab 环境下render_notebook显示空白 问题描述Jupyter-Lab 环境下render_notebook显示空白 首先需要使用pyecharts自带的config来申明一下使用pyecharts的运行环境 from pyecharts.globals import Curre...

MichaelZzzzz的博客 4687

前端怎么打断点,debugger使用教程

前端怎么打断点,debugger使用教程

共同学习,共同成长 1万+

AIGC实战:用ComfyUI和Lora微调打造专属原神角色(含完整工作流)

本文详细介绍了如何利用ComfyUI和Lora微调技术打造专属原神风格角色,涵盖从环境配置、数据集准备到工作流构建和Lora训练的全过程。通过模块化节点设计和高级控制技术,创作者可实现高度个性化的AIGC艺术创作,提升二次元角色生成的效率与质量。

weixin_29185199的博客 348

推荐系统(一)概述

在互联网领域,推荐系统(Recommendation Systems)的应用非常广泛。在音视频方面,如抖音、快手、哔哩等;在电商平台方面,如京东、淘宝、拼多多等。推荐有助于帮助用户快速发现潜在感兴趣的内容(音视频、商品、新闻等信息流),从而提升用户体验,同时有助于提升商业效率。从本文开始,笔者将结合自身在信息流推荐领域的经验,通过系列文章对推荐系统展开介绍。

Jin_Kwok的博客 6084

前端Mock调试导航仪:规则改写+断点拦截实现高效联调

Mock 是现代前端开发中保障接口契约、提升联调效率的核心能力,其本质是构建可预测的数据流控制系统。它基于 HTTP 请求特征(路径、Header、Query、Body)进行条件匹配与响应调度,通过规则改写动态生成符合业务逻辑的模拟数据,借助断点拦截在请求/响应生命周期关键节点实时干预参数与状态。该技术显著降低对后端服务的依赖,支撑异常分支覆盖、弱网模拟、灰度验证等高价值场景。本文聚焦真实项目中高频使用的 Charles 规则改写与断点拦截实践,覆盖金融、电商、SaaS 等多类系统联调需求。

weixin_29230865的博客 82

【推荐100个unity插件之34】在unity中实现和Live2D虚拟人物的交互——Cubism SDK for Unity

Live2D是一款2D建模的软件,常用于游戏,动态壁纸,虚拟主播,游戏公司里面是有专门的ive2D岗位的。游戏里面还有一个经常使用的软件——spine,他做的也是2d的模型,但是他更适合做一些动作,Live2D更适合人物交互方面。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 4989

前端简明教程--代码调试

前端代码调试是前端开发中的一项重要技能,掌握各种调试方法和工具,可以帮助我们快速定位并解决问题。同时,快速布局实现也是前端开发中的一项重要技能,掌握各种布局方式和工具,可以帮助我们快速实现页面布局。希望这篇文章能帮助你更好地掌握前端代码调试和快速布局实现。

A15216110998的专栏 987

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

前端代码断点调试

本文介绍了如何在Vue前端项目中使用VSCode进行断点调试,替代低效的console.log方式。通过配置VSCode的JavaScript Debugger插件,在.vscode/launch.json中设置Chrome调试参数,包括项目URL和源文件映射。启动调试后,可以在JS/TS代码中添加断点,通过浏览器操作触发断点,并利用VSCode的调试界面查看变量、调用堆栈等信息,实现类似后端代码的步进调试功能。这种方法显著提升了前端开发调试效率。

梦幻天空 493

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Chrome DevTools断点调试进阶指南:条件断点、日志点、DOM断点全掌握

作为一名前端开发者,Chrome DevTools 断点调试是你必须掌握的终极技能!🚀 你是否还在使用简单的断点,每次都需要手动暂停程序?本文将带你深入探索 Chrome DevTools 的高级断点调试功能,让你成为真正的调试高手。 Chrome DevTools 提供了多种强大的断点类型,包括条件断点、日志点、DOM断点等,这些功能可以大幅提升你的调试效率和体验。让我们一起来掌握这些实用的

gitblog_01402的博客 891

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

调试艺术:Chrome DevTools 断点实战手册

本文深入解析了Chrome DevTools中各类断点的实战应用技巧,旨在提升前端调试效率。从基础的代码行断点与条件断点,到日志点、DOM断点、事件监听器断点及XHR/Fetch断点,系统讲解了如何在不同场景下精准定位问题。掌握这些调试艺术,能帮助开发者告别低效的console.log,实现从“瞎猜”到“外科手术”式精准排错的飞跃。

903

前端debugger怎么用

Debugger for Firefox 是一款功能强大的 Visual Studio Code(以下简称 VSCode)扩展,它为开发人员提供了在 Firefox 浏览器中调试前端代码的能力。通过此扩展,开发人员可以方便地在 VSCode 中设置断点、查看变量的值以及跟踪代码执行流程,从而更轻松地进行前端开发和调试。本文将详细介绍如何安装和使用 Debugger for Firefox 扩展,并通过一个示例代码演示其基本功能。

Javachichi的博客 668

vscode vue项目代码断点调试

1.下载Debugger for Chrome 2.点击昆虫图标,设置图标 复制以下代码 { "version": "0.2.0", "configurations": [ { "type": "chrome", "request": "launch", "name": "Launch chrom against localhost", ...

qq_40544291的博客 5907

javaWeb前端调试的三种方法

前端调试常用三种方法 1、通过alert() 在js代码适当的位置使用alert方法打印变量的值,执行程序就可以看到浏览器中弹出结果 2、通过console.log()方法 在js代码适当的位置使用cosole.log(),执行程序就可以在浏览器console控制台看到输出结果,也可以直接在浏览器cosole控制台使用该方法打印 3、前端断点调试 类似于后端断点调试的方法,当执行程...

qq_33610816的博客 2775

前端防御那些事儿:如何用一行JS代码实现防调试保护(附解除技巧)

本文探讨了前端代码保护的实用技巧,重点介绍了如何利用一行JS代码中的debugger语句实现防调试保护,通过无限循环或时间检测干扰开发者工具。文章同时提供了禁用断点、条件断点等解除技巧,并分析了代码混淆、反控制台检测等其他保护思路的适用场景与平衡之道。

fern8的博客 898

前端加密对抗——CDP远程调用Debug断点函数python代码实现

觉得这个方法很方便,以前经常遇到开发自己改了加密代码导致同样是AES等加密算法,加密出来不一样,但是用CDP的话就能解决这个问题。上面那篇也没有具体实现的源码,于是自己研究了下,基本实现了,暂时没找到全流程加解密的站,找到了再把返回包解密的代码补上。测试网址:某网站的登录接口。首先设置中开启Protocol Monitor添加协议监视器。

qq_44657899的博客 3155

前端项目断点调试工具

这种方法不仅可以用再原生的html代码当中,当然也可以直接使用在VUE的项目中,无需添加其他的东西,也无需添加其他的插件,直接放入即可,需要哪里停,就在哪里的上一行放就行。在程序当中,你直接将 debugger 放入你想要断点的上一行代码,在执行到这行代码的时候就会自动进行断点,有学习过C语言相关基础的同学,应该能够明白的我的意思吧。然后就去查询相关资料,但是最后用起来,其实用处不大。然后执行的结果就是,可能第一次会没用,不用慌,刷新一下就行了。上代码,这边来一个简单的案例测试吧。又是一个秃头小技巧~~..

m0_58035226的博客 957

前端调试技巧

debugger是 JavaScript 的一个关键字,当浏览器 DevTools 打开时,执行到该语句会自动暂停程序执行。debugger;// 程序会在这里暂停 console.log(data);

jj1245_的博客 720

突破前端反调试--阻止页面不断debugger(F12不能调试)

chrome-devtools前端调试调试前端网页爬虫 问题复现 一次扒某网站的前端代码,打开控制台要看Network,结果发现他们页面一打开控制台就不断的debugger,100ms一次,很影响看页面内容。就像下面这样的 问题分析 每次在断点处停下来的时候页面都会跳到source这个tab页面,也能够看到他的debugger的代码,其实他的实现很简单,只有这一行代码 (fu...

qq_41879417的博客 1万+

VS code中断点调试Vue CLI 3项目

动机 当我发现按照vue的官网教程 cn.vuejs.org/v2/cookbook… 无法实现vue在VS code中的断点调试。 亲测有效的方法 准备工作 vscode和chrome更新到最新版,vscode中安装Debugger for Chrome插件 配置vue.config.js文件(如果没有,在根目录下新增一个) module.exports = { configu...

weixin_33924770的博客 4338
上一篇: SpringMVC中Controller是单例还是多例?如何保证并发安全?
下一篇: Linux内核新动作!
IT界那些事儿
博客等级 码龄6年 2万+粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值