devTools使用
元素(Element)面板
element面板
,包括了页面的一些主要信息,dom节点,样式,切换模拟设备等
- 1 ———— 「选择」用于在页面上选择一个元素,并且在面板上定位到该元素
- 2 ———— 「设备」模拟设备之间的切换,主要是pc/移动端(包括手机,平板),还可以自定义设备,比如一些在APP内使用
webview
的h5
页面,有些特定的标识,可以通用自定义设备初步模拟 - 3 ———— 「样式」显示当前选中元素的样式
- 4 ———— 「计算样式」点击后相当于在右侧打开「计算样式」,方便查看样式、盒模型、计算属性等
- 5 ———— 「布局」显示布局信息,包含
grid
栅格布局和flex
弹性布局 - 6 ———— 「事件监听器」显示当前选中元素上所绑定的事件
- 7 ———— 「DOM断点」显示
DOM
断点列表 - 8 ———— 「属性」显示选择元素的所有属性
- 9 ———— 「无障碍功能」显示整个
DOM
树分析
选择元素
选择元素后,可以做很多事:
- 控制台输入
$0
,可以输出当前DOM
元素 - 查看「样式」、「事件监听器」、「DOM断点」、「属性」等
模拟设备
除了能选择已有的机型外,还可以添加自定义设备
- 其他设置: 媒体查询、标尺、DPR、截图等
样式
- 1 ———— 「过滤」可以过滤
class
类名 / 属性 / 属性值 - 2 ———— 「:hov」启用设置元素状态,一些临时状态很难捕抓到他的属性,可以使用这个来强制设置元素的状态
- :active
- :hover
- :focus
- :visited
- :focus-within 当元素或其任意后代元素被聚焦时匹配
- :focus-visible 当前浏览器在元素聚焦时默认显示轮廓时匹配,可以用于区分「鼠标点击」和「键盘Tab」切换聚焦,浏览器对这两个行为样式判定不同时,可再作样式区分
- :target 目标元素其 id = 当前 URL 片段时匹配
- 3 ———— 「cls」给元素新增
class
类名 - 4 ———— 「+」新增样式
- 5 ———— 盒模型
- 6 ———— 查看计算样式,点击箭头可以定位到设置样式的位置。「全部显示」包含默认的样式。「组合」按
Layout
,Text
,Appearance
,Grid
,Other
布局
显示
grid
,flex
布局元素,以及一些辅助功能
事件监听器
DOM断点
对子元素发生修改、属性发生修改、移除节点时,设置断点,这些情况发生时,会给生效代码自动打上断点,可以清晰看到
DOM
的变化
属性
显示选择元素的所有属性,用来看一些位置信息比较方便
无障碍功能
生成
DOM分析树
控制台(Console)
- 1 ———— 同「5」可以显示不同类型的信息,实现过滤显示
- 2 ———— 清除控制台内容
- 3 ———— 实时表达式
- 4 ———— 通过关键字「过滤」信息
- 5 ———— 同「1」
- 6 ———— 设置控制台展示内容
实时表达式的应用
Console API
日志输出一系列方法的「第一个字符串参数」都可以包含一个或者多个格式符。格式符由%
后面跟一个字母组成,字母代表不同的格式。每个格式符与后面的参数一一对应。
格式符 | 输出结果 |
---|---|
%s | 将值格式化为字符串。 |
%i or %d | 将值格式化为整型数字。 |
%f | 将值格式化为浮点类型 |
%c | 将CSS样式规则应用于通过第二个参数指定的输出字符串。 |
%o | 将值格式化为一个可扩展的DOM元素。就跟在Elements (元素)面板中看到的一样。 |
%O | 将值格式化为一个可扩展的 JavaScript 对象 |
Log 信息
console.log()
方法可以接受一个或多个表达式作为参数,并将他们的值打印到控制台
console.log(object [, object, ...]);
console.log('普通信息');
console.log("%c 使用CSS美化输出信息", "color: red; font-size: x-large");
console.log("字符串的替换和格式化 - Node count: %d, and the time is %f.", document.childNodes.length, Date.now());
log
相似,仅日志级别不同的还有console.info()
: 同log
console.warn()
: 橙字提示console.error()
: 红字提示console.debug()
: 蓝色提示
assert 断言
console.assert()
接受两个参数,如果第一个参数的结果为false
,则该方法会将第二个参数输出到控制台。
console.assert(expression, object);
const x = 5;
const y = 3;
const reason = '5大于3';
console.assert(x < y, { x, y, reason });
group/groupCollapsed/groupEnd 分组
console.group()
分组输出开始
console.groupCollapsed()
分组输出开始,初始是折叠
console.groupEnd()
分组输出结束
console.group("%c 分组", "color: red");
console.log("info");
console.groupEnd();
table 表格
console.table()
方法可以用来查看对象的内容。第二个参数是可选的,是个字符串数组,来指定想显示的属性。
console.table([{a:1, b:2, c:3}, {a:"foo", b:false, c:undefined}]);
console.table([[1,2,3], [2,3,4]]);
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
var family = {};
family.mother = new Person("Susan", "Doyle", 32);
family.father = new Person("John", "Doyle", 33);
family.daughter = new Person("Lily", "Doyle", 5);
family.son = new Person("Mike", "Doyle", 8);
console.table(family, ["firstName", "lastName", "age"]);
time/timeLog/timeEnd 耗时监控
console.time()
传入一个字符串参数来唯一标记这个计时器的ID。
console.timeLog()
传入指定名字。当前执行时间
console.timeEnd()
传入指定的名字。结束指定计时器。结束时,控制台输出计时器开始到结束的耗时。可以用来监控代码执行时间
console.time("MyTimer");
console.timeLog("MyTimer","start time");
var array= new Array(1000000);
for (var i = array.length - 1; i >= 0; i--) {
array[i] = new Object();
};
console.timeLog("MyTimer","end time");
console.timeEnd("MyTimer");
count/countReset 执行次数
console.count()
统计表达式被执行的次数,它接受一个字符串参数用于标记不同的记号。如果两次传入相同的字符串,该方法就会累积计数。console.countReset()
传入的指定字符串相同时,重置次数
function login(user) {
console.count("Login called for user " + user);
}
users = [
'Irish',
'Bakaus',
'Kinlan'
];
users.forEach(function(element, index, array) {
login(element);
});
login(users[0]);
console.countReset("Login called for user Irish");
dir/dirxml DOM树
console.dir(指定元素)
返回DOM树console.dirxml(指定元素)
以xml
形式返回DOM树
trace 跟踪
console.trace()
代码执行顺序
const first = () => { second(); };
const second = () => { third(); };
const third = () => { fourth(); };
const fourth = () => { console.trace(); };
first();
其它命令行API
clear()
———— 清空控制台历史记录,可以在控制台直接执行clear()
,也可以在代码中执行console.clear()
;$0
———— 当前选中的元素,那你们知道$1 - $4
又分别代表什么吗?$()
———— 返回满足指定CSS规则的第一个元素,此方法为document.querySelector()
的简化。$$()
———— 返回满足指定CSS规则的所有元素,此方法为document.querySelectorAll()
的简化。$x()
———— 返回满足指定XPath的所有元素inspect(指定元素)
———— 相当于审查元素monitorEvents(指定元素, 事件)
———— 事件监听,触发时控制台输出event
。解除监听unmonitorEvents(指定元素, 事件)
$_
———— 返回最近一次计算的表达式的值。
$0
$('div')
$x('html/body/div')
源代码(Sources)
断点调试、实时编辑代码
对于生产bug,在生产代码上排查调试是比较麻烦的事情,因为生产代码都是压缩编译过后的代码,可能都不知道代码在哪个文件,找不到对应代码的位置。
Command
+ Option
+ F
断点调试
js代码打断点
- 代码中debugger
- devTools添加断点
- devTools添加条件断点
断点调试:
- 1 ———— 继续下一个断点(
Command
+\
/F8
) - 2 ———— 跳到下一步执行代码,不包含函数内代码(
Command
+'
/F10
) - 3 ———— 执行下一个函数,当前断点若存在函数,则进入当前断点存在的函数内;当前断点若不存在函数,则执行下一步(
Command
+;
/F11
) - 4 ———— 跳出当前函数,回到调用该函数的地方的下一步(
Command
+Shift
+;
/F11
+Shift
) - 5 ———— 单步执行,包含函数内代码(
F9
)
添加条件断点:
断点堆栈列表:
断点作用域:
DOM断点
见
Element
面板的DOM断点
XHR接口断点
事件断点
异常捕获断点
实时编辑代码
我们修改css
样式很容易,直接在「样式
」面板中修改就可以调试。然而,有时候出于一些客观的原因,我们需要在生产环境下,去考虑各种情况下的代码执行,怎么直接在Source
面板下直接修改代码呢?
代码段
可以将一些常用的函数,代码片段,工具等,放到代码段保存起来,而不需要控制台上
console
比较麻烦,只要不去删除,就会一直存在
网络(Network)
network
面板记录在页面上有关每个网络操作的信息,包括详细的时序数据,HTTP请求和响应头,Cookie等
- 1 ———— 继续/停止录制网络日志
- 2 ———— 清除日志
- 3 ———— 过滤,勾选「反转」,则反向过滤
- 4 ———— 搜索:跟
Command
+Option
+F
的搜索功能一样 - 5 ———— 保留日志:页面刷新后原页面的日志仍在
- 6 ———— 停用缓存
- 7 ———— 模拟网速
- 8 ———— 导入/导出HAR文件
浏览器缓存
from memory cache
: 内存缓存from disk cache
: 硬盘缓存
- 强缓存:
Expires
、Cache-Control
- 304协商缓存:
Etag
、If-None-Match
、Last-Modified
、If-Modified-Since
模拟网速
除了已有的网络设置外,还可以添加自定义
如何使用HAR?
HAR(HTTP Archive format HTTP归档),是一种或 JSON
格式的存档格式文件,通用扩展名为 .har
在开发过程中,有的 场景不好复现,比如访问速度慢,请求失败等,由于设备限制,对于我们来说精确的收集数据以及定位问题有一定难度。
比如,作为开发我们可以很熟练的按下F12查看请求,但如果是作为技术支持,没有办法长时间占用对方(客户)的电脑进行问题排查。HAR则可以帮助我们收集所有的HTTP请求。
!!!HAR
文件包含敏感数据:
- 录制过程中所下载网页中的内容。
- 您的
Cookie
,Token
(任何有 HAR 文件的人都可以使用这些 Cookie 冒用您的帐号)。 - 录制过程中提交的所有信息: 个人详细信息、密码、信用卡号码等。
设置
- 使用大量请求行: 预览区域,资源从一行变两行,第二行显示域和路径
- 按框架分组: 页面内嵌
iframe
时使用,将来自同个frame
的网络请求收集在一起 - 显示概览: 显示/隐藏概览区,也就是上面的时间轴,其中花花绿绿的各种横线表示的是一个个的HTTP请求
- 截取屏幕截图: 加载页面时,捕获屏幕截图
请求列表区域
标题栏的对应描述:
Name(名称): 资源的名称。
Status(状态): HTTP 状态代码。
Type(类型): 请求的资源的 MIME 类型。
Initiator(发起): 发起请求的对象或进程。它可能有以下几种值:
Parser(解析器): Chrome 的 HTML 解析器发起了请求。
- Redirect(重定向): HTTP 重定向启动了请求。
- Script(脚本): 脚本启动了请求。
- Other(其他): 一些其他进程或动作发起请求,例如用户点击链接跳转到页面,或在地址栏中输入网址。
Size(大小): 响应头的大小(通常是几百字节)加上响应数据,由服务器提供。
Time(时间): 总持续时间,从请求的开始到接收响应中的最后一个字节
Timeline/Waterfall(时间轴): 显示所有网络请求的可视化统计信息
查看HTTP头信息
查看Cookie
WS
还可查看frames
帧信息
启动器/解析器
鼠标移入当前列启动器项,可以看到如下图所示的调用栈信息
预检请求
CORS 预检请求
这是因为CORS
且请求是复杂请求
的时候,浏览器会自动先向服务器发送预检请求用于确认服务器是否支持该跨域请求。
符合以下条件之一的就是复杂请求:
- 请求的
Method
不是GET
、HEAD
- 请求的
Method
是POST
且Content-Type
不是text/plain
、application/x-www-form-urlencoded
或multipart/form-data
- 请求头中设置了自定义字段
详情可参考MDN CORS
瀑布/时间轴
Queuing(排队)
请求被添加到队列中并等待浏览器发送的时间间隔
排队的原因可能有:
- 被认为比关键资源(如脚本/样式)的优先级低。这经常发生在 images(图像) 上。
- 在等待一个即将被释放的不可用的
TCP socket
。 chrome
中限制HTTP/1.0
和HTTP/1.1
只能为一个域名打开六个TCP
连接- 浏览器正在磁盘缓存中短暂分配空间(通常非常快)。
要解决传统HTTP 1的此问题,您需要实现分域。即用多个子域名提供服务资源,将资源拆分到多个子域中,均匀分配。
Stalled/Blocking (停止/阻塞)
请求出队列到请求真正发出的时间间隔。这个时间包括代理协商的时间
Proxy negotiation(代理协商)
浏览器与代理服务器协商请求的时间
DNS Lookup(DNS寻址)
如果浏览器没有找到DNS缓存的话,那么初始化连接之前还需要DNS寻址
Initial Connection / Connecting (初始连接/连接)
建立连接所需的时间, 包括TCP握手/重试和协商SSL。
SSL
完成SSL握手所用的时间。
Request Sent / Sending (请求已发送/正在发送)
发出网络请求所花费的时间。 通常是几分之一毫秒。
Waiting (TTFB) (等待)
浏览器等待响应的第一个字节所花费的时间,也称为
Time To First Byte
。这个时间 =请求到达服务器的时间
+服务器处理请求准备响应的时间
+响应到达浏览器的时间
高TTFB的原因主要有:
- 客户端和服务器之间的网络条件差,
- 要么,服务器端程序响应很慢。
要解决高TTFB,可以从以下几点着手:
- 去除尽可能多的网络连接。
- 如果只是本地TTFB低,那可能是自身客户端与服务器之间的网络问题。换台机子测试一下,再确定TTFB是否需要改进
- 非本地网络问题,找后端
Content Download / Downloading (内容下载/下载)
接收响应数据所花费的时间。(从接收到第一个字节开始,到下载完最后一个字节结束)
加载过慢,一般就是接收的字节过大,可以:压缩图片,减少文件资源大小
Summary区
应用(Applicant)
检查和管理
Storage(存储)
、Databases(数据库)
和Caches(缓存)
Storage(存储)
本地存储 LocalStorage
会话存储 SessionStorage
相同点:存储的数据将保存在浏览器会话中, 可存储数据量在2.5MB 到 10MB 之间
区别在于:
- 存储在
localStorage
的数据可以长期保留;而当页面会话结束——也就是说,当页面被关闭时,存储在sessionStorage
的数据会被清除。 - 打开多个相同的 URL 的 Tabs 页面,会创建各自的 sessionStorage。
- 存储在
数据库
IndexedDB
浏览器本地数据库,用于存储大量数据,提供查找接口,还能建立索引。但它不属于关系型数据库(不支持
SQL
查询语句)
API
// 打开数据库 open
var request = window.indexedDB.open(databaseName, version);
// 打开数据库失败 onerror
request.onerror = function (event) {
console.log('数据库打开报错');
};
// 成功打开数据库 onsuccess
var db;
request.onsuccess = function (event) {
db = request.result;
console.log('数据库打开成功');
};
// 数据库升级事件 onupgradeneeded。
request.onupgradeneeded = function (event) {
db = event.target.result;
}
// 新建数据库 - 在upgradeneeded事件的监听函数里面完成,因为这时版本从无到有,所以会触发这个事件
request.onupgradeneeded = function (event) {
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('person')) {
// createObjectStore 新建仓库person,以id作为主键,并指定主键为一个递增的整数
objectStore = db.createObjectStore('person', { keyPath: 'id', autoIncrement: true });
}
}
// 新建索引
request.onupgradeneeded = function(event) {
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('person')) {
objectStore = db.createObjectStore('person', { keyPath: 'id', autoIncrement: true });
}
// createIndex 索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
}
// 新增数据 - add
function add() {
// 1. 先新建事务:指定表格名称和操作模式("只读"或"读写")
var request = db.transaction(['person'], 'readwrite')
// 2. 拿到 表 对象
.objectStore('person')
// 3. 向表格写入一条记录
.add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });
request.onsuccess = function (event) {
console.log('数据写入成功');
};
request.onerror = function (event) {
console.log('数据写入失败');
}
}
add();
// 删除数据 - delete
function remove() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.delete(1);
request.onsuccess = function (event) {
console.log('数据删除成功');
};
}
remove();
// 更新数据 - put
function update() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });
request.onsuccess = function (event) {
console.log('数据更新成功');
};
request.onerror = function (event) {
console.log('数据更新失败');
}
}
update();
// 使用主键值进行查询 - get
function read() {
var transaction = db.transaction(['person']);
var objectStore = transaction.objectStore('person');
var request = objectStore.get(1); // 1为主键值
request.onerror = function(event) {
console.log('事务失败');
};
request.onsuccess = function( event) {
if (request.result) {
console.log('Name: ' + request.result.name);
console.log('Age: ' + request.result.age);
console.log('Email: ' + request.result.email);
} else {
console.log('未获得数据记录');
}
};
}
read();
// 使用索引进行查询
function readByIndex() {
var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('李四');
request.onsuccess = function (e) {
var result = e.target.result;
if (result) {
// ...
} else {
// ...
}
}
}
readByIndex();
// 遍历所有数据 - openCursor
function readAll() {
var objectStore = db.transaction('person').objectStore('person');
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
console.log('Id: ' + cursor.key);
console.log('Name: ' + cursor.value.name);
console.log('Age: ' + cursor.value.age);
console.log('Email: ' + cursor.value.email);
cursor.continue();
} else {
console.log('没有更多数据了!');
}
};
}
readAll();
Web SQL
浏览器提供的关系型数据库,跟
IndexedDB
一样用于管理大量数据
Cookie
HttpOnly属性
作用:如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性,即便是这样,也不要将重要信息存入cookie
SameSite属性
作用:当前网页的 URL 与请求目标一致才能带上Cookie
可以设置三个值。
- Strict: 只有当前网页的 URL 与请求目标一致,才会带上 Cookie
- Lax: 默认值,链接
<a href="..."></a>
预加载<link rel="prerender" href="..."/>
GET 表单<form method="GET" action="...">
会发送cookie - None: 必须同时设置
Secure
属性(加密传输
),否则无效。
缓存
清除缓存的方法有哪些?
使用devTools作性能分析的方法
!!! 性能分析需使用「无痕模式」下进行,以确保 Chrome 环境的干净
Lighthouse面板
全自动分析总结,Chrome通过一系列的规则(RAIL)来对网页进行评估分析
性能分析的5个指标
- First Contentful Paint: 内容首次绘制使用时间。
- Largest Contentful Paint: 最大内容渲染时间,可以代表当前页面主要内容展示的时间
- Total Blocking Time: 累积阻塞时长,越小说明页面能够更好的快速响应用户事件。
- Cumulative Layout Shift: 累积布局变化量,分数越低,表明页面的布局稳定性越高,通常低于0.1表示页面稳定性良好。
- Speed Index: 速度指标是一个页面加载性能指标,向你展示明显填充页面内容的速度,此指标的分数越低越好。
之后chrome还会给出优化建议,我们可以判定可用有效建议进行优化
无障碍功能优化
一些无障碍的优化点,不全面可作参考,仍需自己再检测
性能(Performance)面板
分析运行时性能。分析页面的响应、动画和空闲阶段
录制前先点击「垃圾桶」垃圾回收
控制区
进行录制的控制与设置
- 1 ———— 手动开始录制,开始录制后刷新页面,再手动停止录制
- 2 ———— 自动刷新页面,并自动录制,等页面加载完毕后自动停止
- 3 ———— 删除当前录制记录
- 4 ———— 可以切换展示/添加其他录制记录
- 5 ———— 概览区显示屏幕截图
- 6 ———— 显示内存使用情况
- 7 ———— 为了模拟低配设备 ,可以模拟使用低CPU、低网速
概览区
显示CPU占用情况,屏幕截图。
CPU
图表颜色填充越多则CPU
占用越多,颜色都满了,CPU就到底极限
线程区
分析网络请求情况、帧率、代码使用详情等信息
网络请求分析
FPS指数
绿色柱体高度越高,性能越好; 红色意味着帧数已经下降到影响用户体验的程度;橙色是出现部分掉帧
Main代码分析
呈现堆栈火焰图,x轴表示时间,y轴表示调用堆栈
- 结合「聚合区域」的摘要、调用树、事件日志等,可以更加明确地看到代码执行情况
- 部分「代码块」右上角出现红色小三角,是chrome自动帮助识别出有问题的部分,点击可以查看具体问题
内存区
内存使用曲线:将一开始没有进行操作时的内存使用情况作为基准值,与最后停止操作并进行 GC 后的值进行比较,如果有较明显的差距,则说明产生了内存泄漏。
聚合区
包含摘要(统计图表、分析)、自下而上(分析执行耗时)、调用树(事件调用堆栈最顶层的那一步事件)、事件日志(事件调用堆栈树,还加了开始时间)
参考文章:
Chrome Dev Tools 性能分析&调试技巧 从 B 站出发,用 Chrome devTools performance 分析页面如何渲染
分析内存使用情况
Chrome的任务管理器
看内存使用是否稳定
- 内存占用空间: 任务在占用的本地内存,包含DOM
- javascript使用的内存: js堆内存
使用 Performance 可视化检测内存泄漏
内存(Memory)面板
检测到发生了内存泄漏后,可以转到 Memory 面板,进行更进一步的分析。
测试:Memory测试
在浏览器中,常见的内存泄漏包含以下场景:
- 闭包使用不当引起内存泄漏
- 分离的 DOM 节点
- 全局变量和全局绑定的事件
- 遗忘的定时器
查看内存堆快照
查看内存分配时间轴信息
最上方的时间轴中,条形说明在该时间段发生了内存分配。条形的高度对应了分配的内存大小,条形的蓝色部分说明依然存活的对象数量,灰色部分说明已经被 GC 的对象数量。如果较早时间分配的对象依然大量存活,则说明可能有内存泄漏的问题
性能监视器
动画(Animation)面板
捕捉页面里的动画,并根据动画的运动轨迹划分关键帧,我们可以一目了解地知道该关键帧下的哪些元素正在进行哪些样式的变化
面板功能:
- 1 ———— 控制区:清除、暂停/恢复播放、播放速度控制
- 2 ———— 预览区
- 3 ———— 时间轴:重放,时间显示
- 4 ———— 详情区:可以看到有哪些元素,还可以拖动调整修改,样式上会实时出现更新后的样式
注意:动画检查器支持 CSS 动画、CSS 过渡和网络动画,但暂不支持 requestAnimationFrame 动画
安全(Security)
网站的安全性概览,包含证书、网络请求和资源安全性
搜索
找不到文件时,可以通过搜索关键字,来找文件
其它好用的点
命令菜单打开任何功能
Command
+Shift
+P
打开
截图功能
全局可视化编辑
可以用作模拟文字超长时的样式,而不需要在
(Element)面板
中操作,可为便利。包含所有元素
控制台输入:
document.body.contentEditable = true;
// or
document.designMode = 'on'
样式上的一些方便操作
flex布局可视化调整
颜色/阴影可视化调整
字体可视化调整
这是一个实验功能,需要先打开配置:设置 - 实验 - 过滤搜索
font
,勾选Enable new Font Editor tool with this Styles Pane
![]()
元素面板鼠标悬停显示标尺
设置 - 偏好设置 - 元素 - 鼠标悬停显示标尺
控制台输出显示时间
移动端H5调试
- 使用数据线,手机连接电脑(开启文件传输)
- 打开
chrome://inspect
- 可以看到出现h5页面(包含appm内嵌h5,微信浏览器不行)
覆盖率(Covery)面板
标出文件使用情况,有些时候可以用于性能优化
变更(Change)面板
显示当前生效的文件变更,像
git diff
一样的形式
可以修改js,直接修改js文件未生效,则不显示变更,可以开启「启用本地替换」后再修改
More
- 问题
- 新功能
- WebAudio
- WebAuthn
- CSS概览
- 性能数据分析
- 渲染
- 快速来源
- 传感器
- 记录器
- 媒体
- 图层
- 开发者资源
- 网络请求屏蔽
- 网络状况