不要再傻傻使用 requestAnimationFrame 啦?。?!
之前我寫了一個(gè)埋點(diǎn)庫 sunshine-track ,很多人問我為啥批量上報(bào)埋點(diǎn)信息的時(shí)候,用的是 requestIdleCallback 而不是 requestAnimationFrame,今天就解答一下。
sunshine-track 源碼學(xué)習(xí):https://github.com/sanxin-lin/sunshine-track。
一、背景與問題場景
在前端性能監(jiān)控領(lǐng)域,埋點(diǎn)信息上報(bào)是重要的數(shù)據(jù)收集手段。當(dāng)我們需要批量上報(bào)用戶行為數(shù)據(jù)時(shí),傳統(tǒng)同步上報(bào)方案可能導(dǎo)致以下問題:
- 阻塞主線程造成頁面卡頓
- 影響關(guān)鍵渲染流程的執(zhí)行
- 造成不必要的性能損耗
二、核心API對(duì)比分析
1. requestAnimationFrame(rAF)
執(zhí)行時(shí)機(jī):每次重繪前(約16.6ms/次)
設(shè)計(jì)目的:執(zhí)行與渲染相關(guān)的動(dòng)畫邏輯
優(yōu)先級(jí):高(屬于瀏覽器渲染流水線的一部分)
特點(diǎn):
- 保證與屏幕刷新率同步
- 頁面隱藏時(shí)自動(dòng)暫停
2. requestIdleCallback(rIC)
執(zhí)行時(shí)機(jī):瀏覽器空閑時(shí)段
設(shè)計(jì)目的:執(zhí)行低優(yōu)先級(jí)任務(wù)
優(yōu)先級(jí):低(僅在空閑時(shí)執(zhí)行)
特點(diǎn):
- 提供deadline參數(shù)判斷剩余時(shí)間
- 頁面隱藏時(shí)可能不會(huì)執(zhí)行
- 可設(shè)置超時(shí)時(shí)間強(qiáng)制執(zhí)行
三、選擇 requestIdleCallback 的核心原因
1. 執(zhí)行時(shí)機(jī)的合理性
- 埋點(diǎn)上報(bào)是非關(guān)鍵任務(wù),不需要搶占渲染資源
- 避免在渲染關(guān)鍵路徑中插入網(wǎng)絡(luò)I/O操作
- 適合利用瀏覽器的空閑時(shí)段執(zhí)行
2. 優(yōu)先級(jí)控制
- 用戶交互 > 動(dòng)畫渲染 > 空閑任務(wù)
- rAF屬于高優(yōu)先級(jí)(每幀必須執(zhí)行)
- rIC屬于低優(yōu)先級(jí)(可被瀏覽器跳過)
3. 性能影響對(duì)比
指標(biāo) | rAF方案 | rIC方案 |
主線程阻塞概率 | 較高 | 極低 |
影響FPS的可能性 | 可能 | 無 |
CPU使用率 | 較高 | 優(yōu)化空間大 |
執(zhí)行可靠性 | 高 | 需超時(shí)處理 |
4. 容錯(cuò)機(jī)制
四、特殊場景處理建議
1. 頁面關(guān)閉前的上報(bào)
2. 兼容性處理
使用 polyfill 方案:
3. 超時(shí)控制策略
五、最佳實(shí)踐總結(jié)
- 分優(yōu)先級(jí)處理:關(guān)鍵數(shù)據(jù)立即上報(bào),普通數(shù)據(jù)批量處理
- 隊(duì)列機(jī)制:積累足夠數(shù)據(jù)或達(dá)到時(shí)間閾值時(shí)觸發(fā)
- 混合策略:結(jié)合 rIC + 超時(shí)機(jī)制 + 降級(jí)方案
- 性能監(jiān)控:記錄上報(bào)任務(wù)執(zhí)行耗時(shí)
- 錯(cuò)誤重試:對(duì)失敗請(qǐng)求進(jìn)行指數(shù)退避重試
六、結(jié)論
選擇 requestIdleCallback 的核心優(yōu)勢在于其能夠:
- 最大限度減少對(duì)用戶體驗(yàn)的影響
- 智能利用瀏覽器空閑時(shí)段
- 實(shí)現(xiàn)優(yōu)先級(jí)合理的任務(wù)調(diào)度
- 避免與關(guān)鍵渲染流程競爭資源