106 lines
2.5 KiB
Markdown
106 lines
2.5 KiB
Markdown
---
|
|
title: 使用 requestIdleCallback 延迟非关键任务
|
|
impact: MEDIUM
|
|
impactDescription: 在后台任务期间保持 UI 响应
|
|
tags: javascript, performance, idle, scheduling, analytics
|
|
---
|
|
|
|
## 使用 requestIdleCallback 延迟非关键任务
|
|
|
|
**影响等级:中等(在后台任务期间保持 UI 响应)**
|
|
|
|
使用 `requestIdleCallback()` 在浏览器空闲时段调度非关键任务。这能让主线程腾出来处理用户交互和动画,减少卡顿,提升感知性能。
|
|
|
|
**不正确的做法(在用户交互期间阻塞主线程):**
|
|
|
|
```typescript
|
|
function handleSearch(query: string) {
|
|
const results = searchItems(query)
|
|
setResults(results)
|
|
|
|
// 这些操作会立即阻塞主线程
|
|
analytics.track('search', { query })
|
|
saveToRecentSearches(query)
|
|
prefetchTopResults(results.slice(0, 3))
|
|
}
|
|
```
|
|
|
|
**正确的做法(将非关键任务推迟到空闲时间):**
|
|
|
|
```typescript
|
|
function handleSearch(query: string) {
|
|
const results = searchItems(query)
|
|
setResults(results)
|
|
|
|
// 将非关键任务推迟到空闲时段
|
|
requestIdleCallback(() => {
|
|
analytics.track('search', { query })
|
|
})
|
|
|
|
requestIdleCallback(() => {
|
|
saveToRecentSearches(query)
|
|
})
|
|
|
|
requestIdleCallback(() => {
|
|
prefetchTopResults(results.slice(0, 3))
|
|
})
|
|
}
|
|
```
|
|
|
|
**为必须执行的任务设置超时:**
|
|
|
|
```typescript
|
|
// 确保分析事件在 2 秒内触发,即使浏览器一直繁忙
|
|
requestIdleCallback(
|
|
() => analytics.track('page_view', { path: location.pathname }),
|
|
{ timeout: 2000 }
|
|
)
|
|
```
|
|
|
|
**将大任务分块处理:**
|
|
|
|
```typescript
|
|
function processLargeDataset(items: Item[]) {
|
|
let index = 0
|
|
|
|
function processChunk(deadline: IdleDeadline) {
|
|
// 在空闲时间内处理任务(目标:每块 < 50ms)
|
|
while (index < items.length && deadline.timeRemaining() > 0) {
|
|
processItem(items[index])
|
|
index++
|
|
}
|
|
|
|
// 如果还有剩余任务,调度下一块
|
|
if (index < items.length) {
|
|
requestIdleCallback(processChunk)
|
|
}
|
|
}
|
|
|
|
requestIdleCallback(processChunk)
|
|
}
|
|
```
|
|
|
|
**为不支持的浏览器提供降级方案:**
|
|
|
|
```typescript
|
|
const scheduleIdleWork = window.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1))
|
|
|
|
scheduleIdleWork(() => {
|
|
// 非关键任务
|
|
})
|
|
```
|
|
|
|
**适用场景:**
|
|
|
|
- 分析与遥测
|
|
- 将状态保存到 localStorage/IndexedDB
|
|
- 为可能的下一个操作预取资源
|
|
- 处理非紧急的数据转换
|
|
- 非关键功能的懒初始化
|
|
|
|
**不适用场景:**
|
|
|
|
- 需要即时反馈的用户操作
|
|
- 用户正在等待的渲染更新
|
|
- 时间敏感的操作
|