前端性能测量与控制台使用全攻略
在前端开发中,性能测量和调试是确保应用程序高效运行的关键环节。我们可以通过收集性能指标来了解应用程序的性能状况,并利用控制台进行调试和日志记录。下面将详细介绍如何进行性能测量以及控制台的各种使用技巧。
1. 收集性能指标
性能指标的收集对于了解应用程序的性能至关重要。我们可以使用 Fetch 或 Beacon API 将性能指标发送到 API 进行收集和后续分析。这些指标既可以在开发过程中用于调试,也可以用于收集用户的实际性能数据,并将其发送到分析服务进行聚合和分析。
2. 测量页面加载性能
- 问题 :想要收集页面加载事件的时间信息。
- 解决方案 :查找类型为 navigation 的单个性能条目,并从性能条目对象中检索导航时间戳。然后计算这些时间戳之间的间隔,以确定各种页面加载事件所花费的时间。
// There is only one navigation performance entry.
const [navigation] = window.performance.getEntriesByType('navigation');
-
导航时间计算示例 :
| 指标 | 开始时间 | 结束时间 |
| ---- | ---- | ---- |
| 首次字节时间 | startTime | responseStart |
| DOM 交互时间 | startTime | domInteractive |
| 总加载时间 | startTime | loadEventEnd | -
讨论 :导航时间性能条目的 startTime 属性始终为 0。该条目不仅包含时间信息,还包含诸如传输的数据量、HTTP 响应代码和页面 URL 等信息,这些信息有助于确定应用程序首次加载时的响应速度。
3. 测量资源性能
- 问题 :想要获取页面上加载的资源请求的信息。
- 解决方案 :在性能缓冲区中查找资源性能条目。
const entries = window.performance.getEntriesByType('resource');
-
操作步骤 :
- 对于页面上的每个资源,通过计算 startTime 和 responseEnd 属性之间的差值来确定加载时间。
- 资源的 URL 可以在 name 属性中找到。
-
讨论 :使用 Fetch API 进行的任何网络请求也会显示为资源,这使得该 API 对于分析 REST API 端点的实际性能非常有用。页面首次加载时,性能缓冲区包含初始页面加载期间请求的所有资源的条目,后续请求会在发出时添加到性能缓冲区。
4. 查找最慢的资源
- 问题 :想要获取加载时间最长的资源列表。
- 解决方案 :对资源性能条目列表进行排序和过滤。
const slowestResources = window.performance.getEntriesByType('resource')
.sort((a, b) =>
(b.responseEnd - b.startTime) - (a.responseEnd - a.startTime))
.slice(0, 5);
-
操作步骤 :
- 使用 sort 方法比较每个资源的加载时间,并按加载时间降序排序。
- 使用 slice 方法获取排序后数组的前五个元素。
-
讨论 :如果想要获取加载最快的五个资源,可以反转加载时间的比较顺序。
const fastestResources = window.performance.getEntriesByType('resource')
.sort((a, b) =>
(a.responseEnd - a.startTime) - (b.responseEnd - b.startTime))
.slice(0, 5);
5. 查找特定资源的时间
- 问题 :想要查找特定资源请求的时间。
- 解决方案 :使用 window.performance.getEntriesByName 方法按特定 URL 查找资源。
// Look up all requests to the /api/users API
const entries = window.performance.getEntriesByName('https://localhost/api/users', 'resource');
- 讨论 :资源条目的名称是其 URL,getEntriesByName 的第一个参数是 URL,第二个参数表示对资源时间感兴趣。如果给定 URL 有多个请求,返回的数组中将包含多个资源条目。
6. 分析渲染性能
- 问题 :想要记录在页面上渲染某些数据所花费的时间。
- 解决方案 :在渲染开始前创建一个性能标记,渲染完成后再创建另一个标记,然后在两个标记之间创建一个测量来记录渲染时间。
// Create the initial performance mark just before rendering.
window.performance.mark('render-start');
// Create the component and render the data.
const dataView = new DataView();
dataView.render(data);
// When rendering is done, create the ending performance mark.
window.performance.mark('render-end');
// Create a measure between the two marks.
const measure = window.performance.measure('render', 'render-start', 'render-end');
-
操作步骤 :
- 使用 window.performance.mark 创建性能标记。
- 使用 window.performance.measure 在两个标记之间创建测量。
-
讨论 :创建的性能标记和测量会添加到页面的性能缓冲区中,以便稍后查找。可以使用 window.performance.getEntriesByName 方法按名称查找测量。
7. 分析多步骤任务
- 问题 :想要收集多步骤过程的性能数据,包括整个序列的时间和每个步骤的时间。
- 解决方案 :创建多个标记和测量,可以在多个测量计算中使用同一个标记。
window.performance.mark('transactions-start');
const transactions = await fetch('/api/users/123/transactions');
window.performance.mark('transactions-end');
window.performance.mark('process-start');
const analytics = processAnalytics(transactions);
window.performance.mark('process-end');
window.performance.mark('upload-start');
await fetch('/api/analytics', {
method: 'POST',
body: JSON.stringify(analytics),
headers: {
'Content-Type': 'application/json'
}
});
window.performance.mark('upload-end');
console.log('Download transactions:',
window.performance.measure(
'transactions', 'transactions-start', 'transactions-end'
).duration
);
console.log('Process analytics:',
window.performance.measure(
'analytics', 'process-start', 'process-end'
).duration
);
console.log('Upload analytics:',
window.performance.measure(
'upload', 'upload-start', 'upload-end'
).duration
);
console.log('Total time:',
window.performance.measure(
'total', 'transactions-start', 'upload-end'
).duration
);
- 讨论 :通过创建多个标记和测量,可以收集一组任务的性能数据。一个标记可以在多个测量中使用,从而可以为每个步骤创建测量,并为整个任务的持续时间生成最终测量。
8. 监听性能条目
- 问题 :想要在有新的性能条目时得到通知,以便将其报告给分析服务。
- 解决方案 :使用 PerformanceObserver 监听所需类型的新性能条目。对于 API 请求,类型为 resource。
const analyticsEndpoint = 'https://example.com/api/analytics';
const observer = new PerformanceObserver(entries => {
for (let entry of entries.getEntries()) {
// Only interested in 'fetch' entries.
// Use the Beacon API to send a quick request containing the performance
// entry data.
if (entry.initiatorType === 'fetch') {
navigator.sendBeacon(analyticsEndpoint, entry);
}
}
});
observer.observe({ type: 'resource' });
-
操作步骤 :
- 创建一个 PerformanceObserver 实例。
- 使用 observe 方法监听指定类型的性能条目。
- 在回调函数中处理性能条目,并使用 Beacon API 将其发送到分析服务。
-
讨论 :PerformanceObserver 会为每个网络请求触发,包括向分析服务发送的请求。因此,在发送请求之前需要确保给定条目不是分析端点,以避免无限循环的 POST 请求。为了防止在短时间内向分析服务发送大量请求,可以将性能条目收集到缓冲区中,当缓冲区达到一定大小时,将缓冲区中的所有条目一次性发送。
const analyticsEndpoint = 'https://example.com/api/analytics';
// An array to hold buffered entries. Once the buffer reaches the desired size,
// all entries are sent in a single request.
const BUFFER_SIZE = 10;
let buffer = [];
const observer = new PerformanceObserver(entries => {
for (let entry of entries.getEntries()) {
if (entry.initiatorType === 'fetch' && entry.name !== analyticsEndpoint) {
buffer.push(entry);
}
// If the buffer has reached its target size, send the analytics request.
if (buffer.length === BUFFER_SIZE) {
fetch(analyticsEndpoint, {
method: 'POST',
body: JSON.stringify(buffer),
headers: {
'Content-Type': 'application/json'
}
});
// Reset the buffer now that the batched entries have been sent.
buffer = [];
}
}
});
observer.observe({ type: 'resource' });
9. 控制台使用技巧
在调试代码时,控制台是一个非常有用的工具。除了简单的 console.log 之外,还可以对控制台输出进行样式设置、使用不同的日志级别、创建命名记录器、以表格形式显示对象数组、使用控制台计时器和控制台组等。
10. 控制台输出样式设置
- 问题 :想要对控制台日志输出应用一些 CSS 样式。
- 解决方案 :在日志消息中使用 %c 指令来指定要设置样式的文本,并为每个 %c 的使用添加一个包含 CSS 样式的额外参数。
console.log('%cHello world!', 'font-size: 2rem; color: red;');
console.log('This console message uses %cstyled text. %cCool!',
'font-style: italic;',
'font-weight: bold;'
);
- 讨论 :console.log 接受可变数量的参数,对于每个 %c 指令,应该有一个相应的额外参数包含要应用于该部分文本的样式。注意,样式在每个 %c 部分之间会重置。
11. 使用日志级别
- 问题 :想要在控制台中区分信息性、警告性和错误性消息。
- 解决方案 :分别使用 console.info、console.warn 和 console.error 代替 console.log。
console.info('This is an info message');
console.warn('This is a warning message');
console.error('This is an error message');
- 讨论 :这些消息具有不同的样式,并且大多数浏览器允许按日志级别过滤日志消息。警告和错误消息还会显示一个堆栈跟踪,方便追踪错误发生的位置。
12. 创建命名记录器
- 问题 :想要从应用程序的不同模块记录消息,并为消息添加带有指定颜色的模块名称前缀。
- 解决方案 :使用 Function.prototype.bind 方法绑定 console.log 函数,并绑定模块名称前缀和颜色样式。
function createLogger(name, color) {
return console.log.bind(console, `%c${name}`, `color: ${color};`);
}
const rendererLogger = createLogger('renderer', 'blue');
const dataLogger = createLogger('data', 'green');
// Outputs with a blue "renderer" prefix
rendererLogger('Rendering component');
// Outputs with a green "data" prefix
dataLogger('Fetching data');
- 讨论 :通过这种方式调用 bind 会创建一个部分应用的 console.log 函数,该函数会自动添加前缀和颜色。传递给它的任何其他参数都会添加在前缀和颜色样式之后。
13. 以表格形式显示对象数组
- 问题 :想要以易于阅读的方式记录对象数组。
- 解决方案 :将数组传递给 console.table,它会显示一个表格,每个对象属性对应一列,数组中的每个对象对应一行。
const users = [
{ firstName: "John", lastName: "Smith", department: "Sales" },
{ firstName: "Emily", lastName: "Johnson", department: "Marketing" },
{ firstName: "Michael", lastName: "Davis", department: "Human Resources" },
{ firstName: "Sarah", lastName: "Thompson", department: "Finance" },
{ firstName: "David", lastName: "Wilson", department: "Engineering" }
];
console.table(users);
-
操作步骤 :
- 将要显示的对象数组传递给 console.table。
- 可以通过传递第二个参数来限制显示的对象属性。
-
讨论 :console.table 也可以用于显示对象,此时索引列将包含属性名称而不是数组索引。渲染的表格是可排序的,可以点击列名按该列对表格进行排序。
14. 使用控制台计时器
- 问题 :想要计算某些代码执行所花费的时间,用于调试目的。
- 解决方案 :使用 console.time 和 console.timeEnd 方法。
// Start the' loadTransactions' timer.
console.time('loadTransactions');
// Load some data.
const data = await fetch('/api/users/123/transactions');
// Stop the 'loadTransactions' timer.
// Prints: "loadTransactions: <elapsed time> ms"
console.timeEnd('loadTransactions');
-
操作步骤 :
- 使用 console.time 方法启动一个命名计时器。
- 执行要分析的代码。
- 使用 console.timeEnd 方法停止计时器,并在控制台中打印计时器名称和经过的时间。
-
讨论 :与使用 window.performance.mark 和 window.performance.measure 不同,console.time 通常用于临时计时,主要在调试期间使用。其显著区别在于 console.time 和 console.timeEnd 不会将条目添加到性能时间线中,并且一旦调用 console.timeEnd 停止计时器,该计时器就会被销毁。如果需要持久化的计时数据,可能需要使用 Performance API。
15. 使用控制台组
- 问题 :想要更好地组织日志消息组。
- 解决方案 :使用 console.group 创建可展开和折叠的嵌套消息组。
const users = [
{ id: 1, firstName: "John", lastName: "Smith", department: "Sales" },
{ id: 2, firstName: "Emily", lastName: "Johnson", department: "Marketing" },
{ id: 3, firstName: "Michael", lastName: "Davis", department: "Human Resources" },
{ id: 4, firstName: "Sarah", lastName: "Thompson", department: "Finance" },
{ id: 5, firstName: "David", lastName: "Wilson", department: "Engineering" }
];
console.log('Updating user data');
for (const user of users) {
// 这里可以添加更多的日志消息
}
-
操作步骤 :
- 使用 console.group 创建一个新的消息组。
- 在组内记录日志消息。
- 使用 console.groupEnd 结束当前消息组。
-
讨论 :控制台组可以帮助更好地组织和查看日志消息,使调试过程更加清晰。
通过以上介绍的性能测量方法和控制台使用技巧,可以有效地收集和分析前端应用程序的性能数据,并在调试过程中更加高效地定位和解决问题。
前端性能测量与控制台使用全攻略
16. 性能测量与控制台使用的综合流程
为了更清晰地展示前端性能测量和控制台使用的整体流程,下面通过一个 mermaid 流程图来呈现:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B(收集性能指标):::process
B --> C{测量类型?}:::decision
C -->|页面加载性能| D(测量页面加载性能):::process
C -->|资源性能| E(测量资源性能):::process
C -->|渲染性能| F(分析渲染性能):::process
C -->|多步骤任务| G(分析多步骤任务):::process
D --> H(计算页面加载时间):::process
E --> I(查找资源加载时间):::process
F --> J(记录渲染时间):::process
G --> K(收集各步骤时间):::process
H --> L(分析性能数据):::process
I --> L
J --> L
K --> L
L --> M{是否需要调试?}:::decision
M -->|是| N(使用控制台进行调试):::process
M -->|否| O([结束]):::startend
N --> P{调试方式?}:::decision
P -->|输出样式| Q(控制台输出样式设置):::process
P -->|日志级别| R(使用日志级别):::process
P -->|命名记录器| S(创建命名记录器):::process
P -->|表格显示| T(以表格形式显示对象数组):::process
P -->|计时器| U(使用控制台计时器):::process
P -->|控制台组| V(使用控制台组):::process
Q --> W(优化代码):::process
R --> W
S --> W
T --> W
U --> W
V --> W
W --> L
这个流程图展示了从开始收集性能指标,到根据不同的测量类型进行性能测量,然后分析性能数据。如果需要调试,则可以选择不同的控制台使用方式进行调试,调试后优化代码,再重新分析性能数据,形成一个闭环的流程。
17. 性能测量的注意事项
在进行性能测量时,有一些注意事项需要我们关注:
-
环境一致性
:确保在相同的环境下进行多次性能测量,包括浏览器版本、网络状况、设备性能等。不同的环境可能会导致性能指标的波动,影响测量结果的准确性。
-
多次测量取平均值
:由于性能指标可能会受到各种因素的影响,如系统负载、网络抖动等,因此建议进行多次测量,并取平均值作为最终的性能指标。
-
避免干扰因素
:在进行性能测量时,尽量避免同时运行其他可能占用系统资源的程序,以免影响测量结果。例如,关闭不必要的浏览器标签、后台应用程序等。
18. 控制台使用的最佳实践
为了更高效地使用控制台进行调试,以下是一些最佳实践:
-
合理使用日志级别
:根据不同的情况使用不同的日志级别,如使用
console.info
记录一般性信息,使用
console.warn
记录潜在的问题,使用
console.error
记录严重的错误。这样可以方便在调试时快速过滤和定位问题。
-
使用命名记录器
:对于大型项目,使用命名记录器可以清晰地标识出日志信息的来源,便于区分不同模块的日志。
-
及时清理日志
:在调试完成后,及时清理不必要的日志代码,避免在生产环境中输出过多的日志信息,影响应用程序的性能。
19. 性能优化建议
根据性能测量的结果,我们可以采取一些优化措施来提高前端应用程序的性能:
-
优化页面加载时间
:可以通过压缩代码、合并文件、优化图片等方式减少页面的加载时间。例如,使用 Gzip 压缩 CSS 和 JavaScript 文件,将多个小图片合并成一个雪碧图。
-
优化资源加载
:对于不必要的资源,可以采用懒加载的方式,即只有在需要时才加载资源。同时,合理设置资源的缓存策略,减少重复加载。
-
优化渲染性能
:避免在渲染过程中进行大量的 DOM 操作,尽量使用虚拟 DOM 技术。同时,优化 CSS 样式,减少重排和重绘的次数。
20. 总结
前端性能测量和控制台使用是前端开发中不可或缺的环节。通过收集性能指标,我们可以了解应用程序的性能状况,找出性能瓶颈。而控制台则为我们提供了一种简单而有效的调试工具,可以帮助我们快速定位和解决问题。
在实际开发中,我们应该根据具体的需求选择合适的性能测量方法和控制台使用技巧,遵循性能测量的注意事项和控制台使用的最佳实践,并根据性能测量的结果采取相应的优化措施,以提高前端应用程序的性能和用户体验。
希望本文介绍的内容能够帮助你更好地进行前端性能测量和调试,让你的前端应用程序更加高效、稳定。
超级会员免费看
1013

被折叠的 条评论
为什么被折叠?



