跳到主要内容

Chrome 调试技巧

这里收集日常开发中用到的 Chrome 调试技巧。

问题

基础

Chrome DevTools 有 8 个面板:

  • 元素面板(Elements)
  • 控制台面板(Console)
  • 源代码面板(Sources)
  • 网络面板(Network)
  • 性能面板(Performanc)
  • 内存面板(Memory)
  • 应用面板(Application)
  • 安全面板(Security)

提示:安装一些浏览器扩展也会新增【面板】

通用 - copying & saving

copy(...)

Console Panel:

可以通过全局方法 copy() 拿到任何你能拿到的资源

Store as global

Console Panel:

如果你打印了一堆数据,想复用,可以右键选择 “Store as global variable”(保存为全局变量)

依次命名为:temp1temp2temp3、...

保存堆栈信息(Stack trace)

Console Panel:

把控制台打印出来的报错堆栈信息保存到一个文件,便于调试和沟通:

Copy HTML

Element Panel:

右击或者点击在 HTML 元素边上的省略号 (...) 就可以将它 copy 到剪贴板中(【Ctrl + C】也可以复制):

通用 - 快捷键和通用技巧

能直接快速提升开发效率的方式 —— 使用快捷键。

切换 DevTools 窗口的展示布局

  • win 【Ctrl + Shift + D】
  • mac 【CMD + Shift + D】

切换 DevTools 的面板

第 1 种:

  • win 【Ctrl + [】【Ctrl + ]】
  • mac 【CMD + [】【CMD + ]】

第 2 种:

  • win 【Ctrl + 数字】
  • mac 【CMD + 数字】

注意:第 2 种默认被禁用,要去设置开启:

递增/递减

使用上/下箭头键可调整数值,配合修饰键可递增/递减 0.1110

使用场景:CSS 属性实时调试

elements、logs、sources、network 的查找

这四个面板都可以通过以下快捷键查找:

  • win 【Ctrl + F】
  • mac 【CMD + F】

提示:Elements Panel 支持 XPath 查询

通用 - 使用 Command

DevTools 中的 Command 菜单类似于 WebStorm 的 Find Action 和 VSCode 的 Command Palette

启用:【CMD + Shift + P】

注:mac 【CMD + Shift + P】 很容易冲突,可以安装 shortcutdetective 来解决(brew install --cask shortcutdetective),参考:mac下vscode command+shift+p 打开命令面板快捷键失效

三种实用用途:

  • 截图(screen):节点截图、全屏截图(Capture full size screenshot 👍)
  • 切换面板(layout)
  • 切换主题(themem)

通用 - 代码块的使用

直接在 Console Panel 执行:

或在 Source Panel 执行:快捷键【CMD + ENTER】或右键文件选择【Run】

PS:【CMD + K】清空 Console 输出

更快捷:

使用 Command Menu 来执行:

  1. 控制台【CMD + Shfit + P】唤起输入框(或【CMD + P】再按退格键也可以)
  2. 输入 ! 选择要执行的 Snippet

console - console 中的 '$'

$0 用法

在 Element Panel 中,$0 是对我们当前选中的 html 节点的引用

$1 是上一次,$2 是上上次,...之道 $4

$$$ 用法

  • $ = document.querySelector:用法相当于 jQuery 的 $
  • $$ = document.QuerySelectorAll:返回一个节点的数组

$_ 用法

$_ 引用上次执行的结果:

Math.random()

$i 用法

通过 Chrome 插件 Console Importer,可以在 Dev Tools 中直接使用 npm 包。

例如:只需运行 $i('lodash'),几秒后就能获取到对应的库。

$i('lodash')
_.kebabCase('This is amazing!')

console - console 中的 'bug'?

使用 console.log() 打印对象时,如果在两次打印之间修改了对象,可能会发现修改前后的打印结果竟然一样。这种情况会影响调试。

为什么会这样?

  • 因为 console 中打印的对象是以引用方式保存的,在实际展开查看前,对象的值可能已经发生改变。

如何解决?

  • 打印对象的深拷贝
  • 使用 Sources 面板的断点进行调试
  • 使用 JSON.stringify() 将对象序列化后再打印

console - 异步 console

浏览器 API 大多基于 Promise,但在 Console 中使用 Promise 的 .then()async/await 语法不太方便。

示例:

注:测试使用了 https://jsonplaceholder.typicode.com/

fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))

或者:

(async() => {
Response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
json = await Response.json()
console.log(json)
})()

但是注意!实际上 console.log 默认是被 async 包裹的!

也就是说可以直接用 await

Response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
json = await Response.json()

然后我们可以用异步 console 来获取一些有意思的信息:

// Storage 系统的 占用数 和 空闲数
await navigator.storage.estimate()

// 设备的 电池信息
console.table(await navigator.getBattery())

// 媒体能力
query = {type:'file', audio:{contentType: 'audio/ogg'}}
console.table(await navigator.mediaCapabilities.decodingInfo(query))

// Cache storage keys
await caches.keys()

console - Ninja console.log

当断点执行次数太多时,可以使用条件断点来只关注特定条件下的执行结果,这就是条件断点(Conditional breakpoints)

条件断点

右击行号,选择"添加条件断点",输入条件表达式即可设置条件断点。也可以右击已有断点编辑条件。

let a = 0

Array
.from(Array(15))
.map(Math.random)
.forEach((v, i) => {
a = a + v * i
})

🥷 忍者断点

条件断点的特点:

  • 每次执行到断点处都会判断条件
  • 条件为 falsy 值时不会暂停执行

那么,可以把“判断语句”改为 console.log 语句!

console - 自定义格式转换器

关于 formatter

DevTools console 默认的对象转换方式可能不能满足我们的需求,此时可以使用 Custom Formatter 来自定义输出格式。

注意:要先去设置开启选项:

formatter 是一个对象,包含以下方法:

  • header: 控制日志主要展示内容
  • hasbody: 返回 true 时显示展开箭头
  • body: 定义展开后的内容

一个基础的自定义 formatter:

window.devtoolsFormatters = [{
header: (obj) => {
return ['div', {}, `${JSON.stringify(obj, null, 7)}`]
},
hasBody: () => {
return false
}
}]
console.log(window.document)

自定义格式转换器实践

市面上有多种 custom formatter 可选,比如 immutable-devtools 仓库提供的 Immutable.js 结构展示方案。你也可以自己实现一个。

当遇到特殊结构的对象或需要区分的大量日志时,custom formatter 会很有用。

小技巧:对于不需要特殊处理的对象,在 header 方法中返回 null,让 DevTools 使用默认格式化方式。(?)

示例:

A clown formatter:

window.devtoolsFormatters = [{
header: function(obj){
if (!obj.__clown) {
return null; // header null:让 devtools 使用默认格式化方式来处理
}
delete obj.__clown;
const style = `
color: red;
border: dotted 2px gray;
border-radius: 4px;
padding: 5px;
`
const content = `🤡 ${JSON.stringify(obj, null, 2)}`;

try {
return ['div', {style}, content]
} catch (err) { // for circular structures
return null; // use the default formatter
}
},
hasBody: function(){
return false;
}
}]

console.clown = function (obj) {
console.log({...obj, __clown: true});
}

console.log({message: 'hello!'}); // normal log
console.clown({message: 'hello!'}); // a silly log

console - 对象 & 方法

介绍对象和方法的调试技巧。

queryObjects(对象查询)方法

如何查看当前上下文中存在哪些对象?可以使用 DevTools 的 queryObjects 函数。

class Person {
constructor(name, role) {
this.name = name;
this.role = role;
}
}

const john = new Person('Jonh', 'dad')

let kids = [
new Person('Mary', 'kid'),
new Person('Luke', 'kid'),
]

new Person('Lucius', 'uncle') // 不可用的:在代码执行后,对于它的引用并没有留存下来

queryObjects(Person) // 只有 3 个实例

monitor(监听)方法

monitor 是 DevTools 的方法,用于监控函数调用 - 当被监控的函数执行时,控制台会打印出函数名和参数。

class Person {
constructor(name, role) {
this.name = name;
this.role = role;
}
greet() {
return this.getMessage('greeting')
}
getMessage(type) {
if (type === 'greet') {
return `Hello, I'm ${this.name}!`
}
return type
}
}

monitorEvents(监听事件)方法

还有这个监听事件的方法,可以结合上面的做一些事情:

console - console 更多技巧

console.assert

当我们传入的第一个参数为 假 时,console.assert 打印跟在这个参数后面的值:

console.assert(assertion, msg [, subst1, ..., substN]);

示例:

增强 log 的阅读体验

// ❌ Bad
console.log(myName, pencilsCount, timestampNow, id);

// ✅ Good
console.log({ myName, pencilsCount, timestampNow, id });

// ✅ Better
console.table({ myName, pencilsCount, timestampNow, id });

console.table

// ❌ Bad
console.log(bigObject)

// ✅ Good
console.table(bigObject)

// ✅ Better(仅展示想看的字段)
console.table(bigObject, [keyName1, keyName2, ...])

console.dir

当你想查看 DOM 节点的 JS 对象属性时,console.log 只会显示 DOM 节点的 HTML 结构,这时可以使用 console.dir 代替 console.log

给 logs 加上时间戳

调用命令面板开启:

示例:

监测执行时间

  • console.time('标签') 开启计时器,console.timeEnd('标签') 结束并打印耗时
  • 可使用不同标签同时记录多个计时

给你的 console.log 加上 CSS 样式

使用 %c 可以为 console.log 添加 CSS 样式(样式写在第二个参数)。

让 console.log 基于调用堆栈自动缩进

配合 Error 对象的 stack 属性,让你的 log 可以根据堆栈的调用自动缩进:

function log(message) {
console.log(
// 这句话是重点当我们 new 出来的 Error 对象时,会匹配它的stack 信息中的换行符,换行符出现的次数也等同于它在堆栈调用时的深度。
' '.repeat(new Error().stack.match(/\n/g).length - 2) + message
);
}

function foo() {
log('foo');
return bar() + bar();
}

function bar() {
log('bar');
return baz() + baz();
}

function baz() {
log('baz');
return 17;
}

foo();

直接在回调中使用 console.log

当我们需要检查回调函数的参数时,可以直接用 console.log 作为回调函数,这样不仅代码更简洁,还能打印出所有参数:

Bad
getMyLocation(v => console.log(v)) // => {coords: Coordinates}

Good
getMyLocation(console.log) // => {coords: Coordinates} "pretty-accurate"

🚀 使用实时表达式

Console Panel 新增了一个名为 Live Expression 的工具。点击“眼睛”图标即可定义 JavaScript 表达式,结果会实时更新,并支持多个表达式同时定义:

Network - Network 使用技巧

隐藏 network overview

隐藏请求时间轴信息,避免占用面板太多空间:

Request initiator

Network 面板的 Initiator(“启动器“)列显示触发请求的脚本和行号 👍,但可能指向库代码(如 xhr.js),尤其在使用 Axios、zone.js 等时。

将鼠标悬停其上,可查看完整调用堆栈,包含你的文件:

请求过滤

Network Panel 中的过滤器输入框接受 字符串正则表达式,也可以用 属性 过滤:

提示:查看所有属性关键字:【Ctrl + Space】

自定义请求表

重新发送 XHR 请求

XHR/fetch 断点

在 Source Panel 设置 XHR 拦截断点:

可以用来调试页面在请求前后特定值得变化(无需手动在页面源码找地方加 debugger)

元素面板 - 技巧集合

通过 h 来隐藏元素

在元素面板:选中标签元素,按一下【h】可以隐藏元素,再按一下显示

可以用来隐藏敏感信息

拖动 & 放置元素

在元素面板:可以按住拖动元素

使用 control(按钮)来移动元素

ctrl + 上下方向键(win)

cmd + 上下方向键(mac)

元素面板中类似于基础编辑器的操作

可以 ctrl + z

Shadow editor 阴影编辑器

查看元素 style 时,对于 shadow 样式可以点开编辑器弹窗

Timeing function editor 定时函数编辑器

对应 style 也有定时函数编辑器

在元素面板中展开所有的子节点

DOM 断点

说明:

  • 选择 subtree modifications:监听任何它内部的节点被【移除】或者【添加】的事件
  • 选择 attribute modifications:监听任何当前选中的节点被【添加】,【移除】或者【被修改值】的事件
  • 选择 node removal:监听被选中的元素被【移除】的事件

元素面板 - 颜色选择器

只选择你正在用的颜色

开发者工具调色板

直观的选择你的颜色

打开一个文本的调色选择器(是 color 属性, 而不是 background-color) 你会看到 “Contrast ratio(对比度)” 部分。它显示了 文本的颜色 与 开发者工具认为这段文本应该有的背景颜色 之间的对比度。如果这个数值很高,那么你的文本相对于背景来说,更显而易见,但如果这个值接近 1 ,那么文本的颜色几乎不能从背景色中区分。

说明:

  • 在数字边上的 “🚫” 意味着对比度太低了
  • 一个 “✅” 意味着这个颜色遵从 Web Content Accessibility Guidelines (WCAG) 2.0 的 AA 声明,这意味着对比值至少为 3
  • “✅ ✅” 意味着满足了 AAA 声明

Drawer - Drawer 常识

如何打开 Drawer?

按 Esc 打开

Drawer 里面到底有什么?

除了 Console 还有很多:

也可以调起 command 弹窗输入打开,前面加个“show“:

  • Animations
  • Changes
  • Console
  • Coverage
  • Network conditions
  • Performance monitor
  • Quick source
  • Remote devices
  • Rendering
  • Request blocking
  • Search
  • Sensors
  • What’s new

控制传感器

sensors 设置模拟特定位置:

模拟网络状态

network conditions

拿到 source

quick source

快速查看源码

检查代码 coverage

coverage

检查你修改的内容

changes

这里打开在开发者工具改过的文件,会显示 git 一样的双色变动提示

Workspace - workspace 技巧

直接在 chrome 修改我们的本地文件

在 chrome 中修改你的文件

把项目的文件夹直接拖到 Source 面板,DevTools 会将你做出的修改同步到系统的文件中

workspace 支持即时同步样式

设置好 workspace 后,可以在 Sources 面板编辑代码并保存到本地。对于样式修改,在 Elements 面板中编辑会立即同步到文件中。

为新选择器选择目标位置

如果没有想要的选择器,可以按下New Style Rule 按钮

workspace 允许 css 注入

设置工作区后,CSS 的修改会自动保存到文件系统并立即在页面上生效,无需刷新。

资源

参考