如何在iOS(UIKit、SwiftUI)生产环境检测滚动卡顿并记录至分析对象?
生产环境检测滚动卡顿的代码实现方案
当然有,下面是几种经过实践验证的代码实现方案,可以在生产环境中检测用户的滚动卡顿情况并记录到你的分析对象中:
方案一:基于requestAnimationFrame的帧间隔检测
滚动卡顿的核心是帧率下降——60fps的理想状态下每帧间隔约16.7ms,若连续多帧间隔远超这个值,就判定为卡顿。
// 假设你的分析对象已定义 const analytics = { recordScrollJank: (duration, dropFrameCount) => { // 替换为你的实际上报逻辑(比如发后端、存本地) console.log(`滚动卡顿:持续${duration}ms,丢帧${dropFrameCount}帧`); } }; let lastFrameTime = null; let jankStartTime = null; let dropFrameCount = 0; const THRESHOLD = 16.7 * 2; // 超过2倍理想帧间隔判定为卡顿 function checkFrameInterval() { const currentTime = performance.now(); const frameGap = currentTime - lastFrameTime; if (frameGap > THRESHOLD) { jankStartTime = jankStartTime || currentTime; dropFrameCount++; } else { // 卡顿结束,记录数据 if (jankStartTime) { const totalDuration = currentTime - jankStartTime; analytics.recordScrollJank(totalDuration, dropFrameCount); jankStartTime = null; dropFrameCount = 0; } } lastFrameTime = currentTime; requestAnimationFrame(checkFrameInterval); } // 滚动开始时启动检测(避免无意义的持续运行) window.addEventListener('scroll', () => { if (!lastFrameTime) { lastFrameTime = performance.now(); requestAnimationFrame(checkFrameInterval); } }, { passive: true }); // 滚动停止1秒后终止检测,节省资源 let scrollStopTimer; window.addEventListener('scroll', () => { clearTimeout(scrollStopTimer); scrollStopTimer = setTimeout(() => { // 若还有未结束的卡顿,先记录再停止 if (jankStartTime) { const totalDuration = performance.now() - jankStartTime; analytics.recordScrollJank(totalDuration, dropFrameCount); jankStartTime = null; dropFrameCount = 0; } lastFrameTime = null; }, 1000); }, { passive: true });
方案二:利用Performance API记录滚动耗时
通过Performance API的标记和测量功能,精准统计滚动过程的耗时,判断是否存在卡顿:
const analytics = { recordScrollJank: (measureName, duration) => { console.log(`滚动卡顿:${measureName} 耗时${duration}ms`); } }; window.addEventListener('scroll', () => { const startMark = `scroll-start-${Date.now()}`; performance.mark(startMark); // 在下一帧计算滚动耗时 requestAnimationFrame(() => { performance.mark('scroll-end'); performance.measure('scroll-duration', startMark, 'scroll-end'); const measureResult = performance.getEntriesByName('scroll-duration')[0]; // 阈值可根据业务需求调整 if (measureResult.duration > 30) { analytics.recordScrollJank('scroll-duration', measureResult.duration); } // 清理性能标记,避免内存占用 performance.clearMarks(startMark); performance.clearMarks('scroll-end'); performance.clearMeasures('scroll-duration'); }); }, { passive: true });
方案三:scroll事件+定时器的简易检测
实现逻辑简单,适合快速排查滚动卡顿情况:
const analytics = { recordScrollJank: () => { console.log('检测到滚动卡顿'); } }; window.addEventListener('scroll', () => { let isJank = false; // 设定20ms的预期执行时间 const delayTimer = setTimeout(() => { isJank = true; }, 20); requestAnimationFrame(() => { clearTimeout(delayTimer); if (isJank) { analytics.recordScrollJank(); } }); }, { passive: true });
注意事项
- 所有滚动事件监听必须加
{ passive: true },避免阻塞主线程。 - 可给检测逻辑加节流处理,防止频繁触发上报影响性能。
- 卡顿阈值(如16.7ms、30ms)可根据不同设备性能调整。
- 生产环境要加错误捕获,避免检测代码本身引发问题。
内容的提问来源于stack exchange,提问作者CarlosAndres
相关产品推荐
相关产品推荐

