导读:本期聚焦于小伙伴创作的《如何用SQLite记录和分析Resource Timing资源加载性能数据》,敬请观看详情。浏览器提供的Resource Timing接口能采集页面所有资源的加载耗时,但数据散落在客户端难以聚合。把指标写入SQLite后,可利用SQL做多维查询与离线分析。本文说明建表结构、采集navigation和resource类型条目、通过performance.getEntriesByType获取字段并批量插入,以及用索引优化慢查询。还会对比内存数组与SQLite在万级记录下的统计效率,指出直接序列化JSON丢失明细的误区,并给出按域名分组计算平均DNS、TCP、响应时间的实践方案。

在前端性能优化工作中,Resource Timing API 是浏览器原生提供的资源加载度量工具。它能够精确记录每一个图片、脚本、样式表、接口请求从开始到结束各阶段的时间戳。然而这些原始数据仅存在于当前页面会话中,若想跨页面、跨用户做长期分析与问题排查,就需要一个轻量且易嵌入的存储方案,SQLite 正是此类场景下的理想选择。

如何用SQLite记录和分析Resource Timing资源加载性能数据

一、Resource Timing 基础与数据结构

Resource Timing 分为两个主要类型:navigation 和 resource。navigation 描述页面本身加载过程,resource 描述具体子资源请求。通过 performance.getEntriesByType('resource') 可以拿到当前页面所有子资源条目,每个条目包含 namestartTimeresponseEnddomainLookupStart 等字段。

这些字段以高精度时间戳呈现,单位多为毫秒。由于浏览器限制,部分跨域资源会出于安全考虑隐藏详细阶段数据,此时需要使用 Timing-Allow-Origin 响应头开放权限。理解字段含义是后续写入 SQLite 的前提,例如 domainLookupEnd - domainLookupStart 即为 DNS 查询耗时。

1.1 核心字段说明

常用的关键字段包括 name(资源 URL)、initiatorType(资源类型如 script、img)、transferSize(传输字节数)、duration(总耗时)。在采集时建议同时记录 entryType 以区分 navigation 与 resource。

为了避免重复存储,可对 name 做截断或提取域名。因为完整 URL 可能带有动态参数,直接做主键会导致大量冗余。一般实践中会将域名单独提取为一列,便于后续分组统计。

二、SQLite 表结构设计

针对 Resource Timing 数据特点,建立一张资源性能表。使用自增主键、资源 URL、域名、类型、各阶段耗时及采集时间等字段。SQLite 支持无类型或弱类型列,但显式声明类型有助于工具识别。

建表时应为常用查询列如域名、类型、采集时间建立索引。万级数据下,没有索引的 LIKE 查询会明显变慢。以下为推荐表结构:

CREATE TABLE resource_timing (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  res_name TEXT NOT NULL,
  domain TEXT,
  initiator_type TEXT,
  entry_type TEXT,
  dns_time REAL,
  tcp_time REAL,
  response_time REAL,
  duration REAL,
  transfer_size INTEGER,
  collect_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_domain ON resource_timing(domain);
CREATE INDEX idx_collect ON resource_timing(collect_time);

2.1 字段计算方式

DNS 耗时等于 domainLookupEnd - domainLookupStart,TCP 耗时等于 connectEnd - connectStart,响应耗时可用 responseEnd - responseStart 表示。在插入前于 JavaScript 端计算好数值,能减轻数据库运算压力。

若某些字段在无权限时为 0,应在写入时做空值或负值标记,防止统计均值时被误算。可通过判断 domainLookupStart 是否为 0 来识别是否拿到完整数据。

三、前端采集与批量写入

在页面 load 事件之后,调用 performance.getEntriesByType('resource') 遍历结果。为降低写入频率,可先收集到数组,再使用 SQLite 的事务批量插入。若在 Electron 或移动端混合应用中,可直接通过本地 SQLite 库执行。

下面示例展示如何用 JavaScript 组织数据,并拼装 SQL 插入语句。注意代码内所有小于号与大于号均已转义,以符合存储规范。

function collectAndInsert(db) {
  var entries = performance.getEntriesByType('resource');
  var sqlParts = [];
  for (var i = 0; i < entries.length; i++) {
    var e = entries[i];
    var url = e.name;
    var domain = url.split('/')[2] || 'unknown';
    var dns = e.domainLookupEnd - e.domainLookupStart;
    var tcp = e.connectEnd - e.connectStart;
    var resp = e.responseEnd - e.responseStart;
    sqlParts.push(
      "('" + url + "','" + domain + "','" +
      e.initiatorType + "','resource'," +
      dns + "," + tcp + "," + resp + "," +
      e.duration + "," + e.transferSize + ")"
    );
  }
  if (sqlParts.length === 0) return;
  var sql = "INSERT INTO resource_timing (res_name,domain,initiator_type,entry_type,dns_time,tcp_time,response_time,duration,transfer_size) VALUES " + sqlParts.join(',');
  db.run(sql);
}

3.1 事务提升性能

单条 INSERT 在百条数据时就会有肉眼可见延迟。使用 BEGIN TRANSACTIONCOMMIT 包裹批量插入,能将写入耗时从秒级降至毫秒级。在 Node.js 的 sqlite3 模块中,可使用 db.serialize 配合 db.run('BEGIN') 实现。

另外建议限制单次采集条目数,例如只保留耗时超过 100 毫秒的资源,过滤掉大量极小图标,既节省空间又突出慢请求。

四、用 SQL 做资源分析

数据落盘后,即可发挥 SQLite 的查询优势。比如统计各域名平均 DNS 与响应时间,快速定位劣质 CDN。以下查询按域名分组:

SELECT
  domain,
  COUNT(*) AS cnt,
  AVG(dns_time) AS avg_dns,
  AVG(tcp_time) AS avg_tcp,
  AVG(response_time) AS avg_resp
FROM resource_timing
WHERE entry_type = 'resource'
GROUP BY domain
ORDER BY avg_resp DESC
LIMIT 20;

4.1 对比内存数组方案

若仅用前端内存数组存储,万条记录排序与过滤需手写循环,且无法持久化。SQLite 借助索引与查询优化器,在相同数据量下分组统计通常快数倍,并允许离线用命令行或可视化工具复查。

常见误区是把整批 Timing 数据直接 JSON.stringify 存为一个字段。这种做法虽简单,却丧失按阶段筛选能力,后期想查某个域名必须解析全部文本,效率极低。

五、注意事项与扩展

Resource Timing 缓冲区有上限,超过后早期条目会被丢弃。可监听 onresourcetimingbufferfull 事件并调用 performance.clearResourceTimings() 前先采集。对于 SPA 应用,路由切换时的资源也应周期性收集。

SQLite 文件可随应用打包或放置用户目录,配合定时任务上传至服务端做横向对比。若需更细粒度,可将 navigation 条目也写入同表,通过 entry_type 区分,统一分析首屏与子资源性能。

SQLiteResource_Timing前端性能监控修改时间:2026-08-12 01:18:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。