Skip to content

前端调试高级技巧

记录一些不太常见但非常实用的前端调试技巧,帮助快速定位和解决问题。

一、函数自动断点

1. debug() 给函数加断点

直接在 Console 中使用 debug() 可以给任何函数添加自动断点:

javascript
// 给 window.open 加断点,任何调用都会自动暂停
debug(window.open);

// 给自定义函数加断点
debug(myFunction);

// 取消断点
undebug(window.open);

2. monitor() 监控函数调用

javascript
// 监控函数调用,会在 console 打印调用信息和参数
monitor(fetch);
monitor(XMLHttpRequest.prototype.open);

// 取消监控
unmonitor(fetch);

3. 监控所有函数调用

javascript
// 监控对象的所有方法调用
const obj = { foo() {}, bar() {} };
Object.keys(obj).forEach((key) => {
  if (typeof obj[key] === 'function') {
    monitor(obj[key]);
  }
});

二、页面跳转与重定向调试

1. 监听 Navigation API

javascript
// 在 Console 执行,可以捕获所有页面跳转
navigation.addEventListener('navigate', (e) => {
  console.log('页面跳转:', e.destination.url);
  debugger; // 自动断点
});

// 或者只监听特定 URL
navigation.addEventListener('navigate', (e) => {
  if (e.destination.url.includes('target-page')) {
    debugger;
  }
});

2. 拦截 location 相关跳转

javascript
// 拦截 location.href 赋值
let _href = location.href;
Object.defineProperty(location, 'href', {
  get() {
    return _href;
  },
  set(val) {
    console.log('location.href 被设置为:', val);
    debugger;
    _href = val;
  },
});

// 拦截 location.replace
const originalReplace = location.replace;
location.replace = function (url) {
  console.log('location.replace 调用:', url);
  debugger;
  return originalReplace.call(this, url);
};

3. 拦截 window.open

javascript
const originalOpen = window.open;
window.open = function (...args) {
  console.log('window.open 调用:', args);
  debugger;
  return originalOpen.apply(this, args);
};

4. Chrome DevTools 设置自动暂停

在 Sources 面板右侧勾选:

  • Pause on caught exceptions - 捕获异常时暂停
  • Pause on uncaught exceptions - 未捕获异常时暂停

在 Network 面板勾选:

  • Preserve log - 跨页面保留日志

5. 拦截 304 重定向

在 Network 面板:

  1. 右键请求 → Block request URL(阻止请求)
  2. 或在 Sources → Overrides 中覆盖响应

在 Console 中:

javascript
// 拦截所有 fetch 请求
const originalFetch = window.fetch;
window.fetch = function (...args) {
  console.log('Fetch 请求:', args[0]);
  return originalFetch.apply(this, args).then((response) => {
    if (response.status === 304 || response.redirected) {
      console.log('重定向/304:', response.url);
      debugger;
    }
    return response;
  });
};

三、DevTools 弹出窗口技巧

1. 自动打开 DevTools

在页面最开始执行:

javascript
// 方法1:延迟执行,确保能看到初始请求
setTimeout(() => {
  debugger
}, 0)

// 方法2:在 HTML 的 <head> 最前面加
<script>debugger;</script>

2. 设置弹出窗口默认打开 DevTools

在已打开的 DevTools 中执行:

javascript
// 让所有新开窗口都自动打开 DevTools
// 需要在 Chrome 启动时加参数:
// --auto-open-devtools-for-tabs

或使用 Puppeteer 等工具:

javascript
const browser = await puppeteer.launch({
  devtools: true, // 自动打开 DevTools
});

3. 快速切换 DevTools 停靠位置

快捷键:Cmd+Shift+D(Mac)或 Ctrl+Shift+D(Windows)

四、XHR/Fetch 断点

1. 在 Sources 面板设置 XHR 断点

Sources → XHR/fetch Breakpoints → 添加 URL 包含的字符串

例如输入 api/user 会在所有包含该路径的请求时暂停

2. 全局拦截所有请求

javascript
// 拦截所有 XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
  console.log('XHR:', method, url);
  if (url.includes('target-api')) {
    debugger;
  }
  return originalOpen.apply(this, arguments);
};

// 拦截所有 fetch
const originalFetch = window.fetch;
window.fetch = function (...args) {
  console.log('Fetch:', args[0]);
  debugger;
  return originalFetch.apply(this, args);
};

3. 查看请求堆栈

在 Network 面板点击请求,切换到 Initiator 标签,可以看到请求的完整调用堆栈

五、Event Listener 断点

1. 在 Sources 面板设置事件监听断点

Sources → Event Listener Breakpoints → 勾选需要监听的事件类型

常用的:

  • Mouse → click
  • Keyboard → keydown
  • Timer → setTimeout/setInterval
  • Script → Script First Statement(脚本首次执行时断点)

2. 使用 monitorEvents()

javascript
// 监控元素的所有事件
monitorEvents(document.body);

// 监控特定事件
monitorEvents(document.body, 'click');

// 监控多个事件
monitorEvents(document.body, ['click', 'keydown']);

// 取消监控
unmonitorEvents(document.body);

3. 查看元素的所有监听器

javascript
// 查看元素绑定的所有事件监听器
getEventListeners(document.body);

// 查看特定事件
getEventListeners(document.body).click;

4. 移除所有事件监听器

javascript
// 克隆节点可以移除所有监听器
const element = document.querySelector('#target');
const clone = element.cloneNode(true);
element.parentNode.replaceChild(clone, element);

六、DOM 断点

在 Elements 面板右键元素 → Break on:

  1. subtree modifications - 子节点增删改时断点
  2. attribute modifications - 属性修改时断点
  3. node removal - 节点删除时断点

实用场景:

  • 找到是谁删除了某个元素
  • 找到是谁修改了某个属性
  • 调试动态插入的内容

七、Console 高级技巧

1. $0-$4 快捷引用

  • $0 - Elements 面板当前选中的元素
  • $1-$4 - 之前选中的元素
javascript
$0; // 当前选中的元素
$0.remove(); // 快速删除元素
$0.style.background = 'red'; // 快速修改样式

2. $() 和 $$() 选择器

javascript
$('div'); // 等同于 document.querySelector('div')
$$('div'); // 等同于 document.querySelectorAll('div') 并转为数组

// 快速操作
$$('img').forEach((img) => console.log(img.src));

3. copy() 复制数据

javascript
// 复制对象到剪贴板
copy(document.body.innerHTML);
copy(localStorage);
copy(JSON.parse(someData));

// 复制表格数据
copy($$('table tr').map((tr) => $$(tr, 'td').map((td) => td.textContent)));

4. queryObjects() 查找内存对象

javascript
// 查找所有某个类的实例
class MyClass {}
const obj = new MyClass();
queryObjects(MyClass); // 返回所有 MyClass 实例

5. 条件断点和日志断点

在代码行号上右键:

  • Add conditional breakpoint - 只在条件为 true 时断点
  • Add logpoint - 不暂停,只打印日志
javascript
// 条件断点示例
i === 100; // 只在 i 等于 100 时暂停

// 日志断点示例
console.log('i =', i); // 不暂停,直接打印

八、Network 调试技巧

1. Replay XHR

在 Network 面板右键请求 → Replay XHR,可以重新发送请求

2. Copy as fetch/cURL

右键请求 → Copy → Copy as fetch/Copy as cURL

可以直接在 Console 或终端重放请求

3. Block Request URL

右键请求 → Block request URL,模拟请求失败

或在 Network conditions → Block request URL patterns 批量添加

4. Throttling 网络限速

Network 面板顶部选择预设:

  • Fast 3G
  • Slow 3G
  • Offline

或自定义限速规则

5. Preserve log 跨页面保留日志

勾选 Network 面板的 Preserve log,可以在页面跳转后保留之前的请求记录

九、本地覆盖线上代码

1. Overrides 本地覆盖

Sources → Overrides → Enable Local Overrides → 选择文件夹

之后在 Sources 中修改任何文件都会保存到本地,刷新页面后生效

2. Snippets 代码片段

Sources → Snippets → New snippet

保存常用的调试代码,随时执行:

javascript
// 例如:显示所有图片的 src
console.table(
  Array.from(document.images).map((img) => ({
    src: img.src,
    alt: img.alt,
    size: `${img.width}x${img.height}`,
  })),
);

十、黑盒脚本

1. Blackboxing 忽略第三方代码

Settings → Blackboxing → Add pattern

添加不想调试的脚本,如 /node_modules//jquery/

调试时会自动跳过这些脚本

2. 标记为黑盒

在调用堆栈中右键 → Blackbox script

十一、Performance 性能调试

1. Performance Monitor

Cmd+Shift+P → Show Performance Monitor

实时查看:

  • CPU 使用率
  • JS 堆大小
  • DOM 节点数
  • 事件监听器数量
  • 布局/重绘次数

2. FPS Meter

Rendering → Frame Rendering Stats

显示实时帧率

3. Paint Flashing

Rendering → Paint flashing

高亮显示重绘区域(绿色闪烁)

4. Layout Shift Regions

Rendering → Layout Shift Regions

高亮显示布局偏移区域(蓝色)

十二、内存泄漏调试

1. Memory 面板快照对比

  1. 执行操作前拍快照
  2. 执行操作(如创建大量元素)
  3. 再拍一次快照
  4. 对比两次快照,找出新增的对象

2. 查找 Detached DOM

在 Memory 快照中搜索 Detached,找到已从 DOM 树移除但仍在内存中的节点

3. 录制分配时间线

Memory → Allocation instrumentation on timeline

可以看到内存分配的时间线,找到内存持续增长的点

4. 强制垃圾回收

在 Memory 面板点击垃圾桶图标,强制执行 GC

十三、移动端调试

1. Remote Debugging

Chrome DevTools → 更多工具 → Remote devices

通过 USB 调试 Android 设备

2. Device Mode

切换到设备模式(Cmd+Shift+M)

可以:

  • 模拟不同设备
  • 旋转屏幕
  • 模拟触摸事件
  • 截取设备屏幕截图

3. 查看触摸事件

Rendering → Show touch/click highlights

4. 模拟传感器

More tools → Sensors

模拟:

  • 地理位置
  • 设备方向
  • 空闲状态

十四、Console 的隐藏技巧

1. console.table()

javascript
// 表格形式展示数组/对象
console.table([
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
]);

2. console.time() / console.timeEnd()

javascript
console.time('fetch');
await fetch('/api/data');
console.timeEnd('fetch'); // 输出:fetch: 234.56ms

3. console.trace()

javascript
function a() {
  b();
}
function b() {
  c();
}
function c() {
  console.trace();
}
a(); // 输出完整调用栈

4. console 的 CSS 样式

javascript
console.log('%c 大号红色文字', 'font-size: 20px; color: red;');
console.log('%c 背景色 %c 普通文字', 'background: yellow; color: black;', '');

5. 条件打印

javascript
// 只在条件为假时打印
console.assert(value > 0, '值必须大于0', value);

十五、实战技巧汇总

1. 快速定位页面卡顿

javascript
// 在 Console 执行,监控长任务
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.duration > 50) {
      console.warn('长任务:', entry.duration, 'ms', entry);
      debugger;
    }
  }
}).observe({ entryTypes: ['longtask'] });

2. 监控所有 Ajax 请求

javascript
// 统一拦截,打印所有请求和响应
const hookAjax = () => {
  const open = XMLHttpRequest.prototype.open;
  const send = XMLHttpRequest.prototype.send;

  XMLHttpRequest.prototype.open = function (method, url) {
    this._url = url;
    this._method = method;
    return open.apply(this, arguments);
  };

  XMLHttpRequest.prototype.send = function () {
    this.addEventListener('readystatechange', function () {
      if (this.readyState === 4) {
        console.log(`${this._method} ${this._url}`, {
          status: this.status,
          response: this.responseText,
        });
      }
    });
    return send.apply(this, arguments);
  };
};

hookAjax();

3. 监控特定元素的所有变化

javascript
// 使用 MutationObserver
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    console.log('DOM 变化:', mutation);
    debugger;
  });
});

observer.observe(document.body, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
});

4. 找到页面上的内存泄漏

javascript
// 定期检查节点数量
let lastCount = 0;
setInterval(() => {
  const count = document.querySelectorAll('*').length;
  if (count > lastCount) {
    console.warn(`DOM 节点增加: ${lastCount} -> ${count}`);
  }
  lastCount = count;
}, 1000);

5. 导出 HAR 文件

Network 面板右键 → Save all as HAR with content

可以保存所有网络请求,用于后续分析或分享

十六、其他实用技巧

1. 查看元素的所有 CSS

javascript
// 获取元素的所有计算样式
const styles = getComputedStyle($0);
copy(Object.fromEntries(Array.from(styles).map((key) => [key, styles[key]])));

2. 快速禁用所有断点

Sources 面板 → Deactivate breakpoints(快捷键:Cmd+F8)

3. 查找未使用的 CSS/JS

Coverage 面板(Cmd+Shift+P → Show Coverage)

红色表示未执行的代码,可以用来优化文件大小

4. 模拟弱网环境下的请求超时

javascript
// 设置 fetch 超时
const fetchWithTimeout = (url, timeout = 3000) => {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)),
  ]);
};

5. Chrome Flags 实验性功能

访问 chrome://flags/,开启实验性功能:

  • Enable parallel downloading - 并行下载
  • Ignore X-Frame-Options - 忽略 iframe 限制
  • Same-site by default cookies - 测试 Cookie 策略

总结

以上技巧涵盖了:

  • 函数和事件的自动断点
  • 页面跳转和重定向的调试
  • 网络请求的拦截和重放
  • DOM 变化的监控
  • 性能和内存的分析
  • 移动端的调试方法

掌握这些技巧可以大大提高调试效率,快速定位和解决前端问题。建议根据实际场景灵活运用,逐步建立自己的调试工具库。