文章目录
- 先给结论
- 先给一张总对照表
- 一、setTimeout:只是“往后丢一会儿”
- 代码
- 实际发生了什么?
- 为什么不能解决卡顿?
- 什么时候还能用?
- 二、debounce:减少执行次数,不是调度
- 代码
- 它解决的是什么?
- 它没解决什么?
- debounce 的适用场景
- 三、startTransition:React 级别的“让路”
- 代码
- 它到底做了什么?
- 时间线对比(非常关键)
- setTimeout / debounce
- startTransition
- 四、三者最容易搞混的一点
- 五、正确的组合方式(生产级)
- debounce + startTransition(最强)
- 错误组合(常见)
- 六、一个表格搜索的真实决策树
- 七、为什么 React 团队不推荐 setTimeout?
- 八、用一句工程化标准帮你记住
- 九、最后一段“刻进脑子”的话
先给结论
setTimeout / debounce = 时间层面的延迟
startTransition = UI 优先级 & 可中断调度
它们解决的是完全不同的问题。
先给一张总对照表
| 维度 | setTimeout | debounce | startTransition |
|---|---|---|---|
| 本质 | JS 定时器 | JS 定时策略 | React 调度语义 |
| 是否理解 UI | ❌ | ❌ | ✅ |
| 是否可中断 | ❌ | ❌ | ✅ |
| 是否降低计算次数 | ❌ | ✅ | ❌ |
| 是否防抖 | ❌ | ✅ | ❌ |
| 是否解决卡输入 | ❌ | ⚠️ 部分 | ✅ |
| React 推荐 | ❌ | ⚠️ | ✅ |
一、setTimeout:只是“往后丢一会儿”
代码
setTimeout(()=>{setList(filter(data))},0)实际发生了什么?
- 把任务放进macrotask queue
- 当前 call stack 执行完再跑
- 但一旦开始执行,就不能被打断
为什么不能解决卡顿?
输入 ↓ JS 空闲 ↓ setTimeout callback 开始 ↓ filter(data) 占满 500ms ↓ 输入仍然卡它只是换了个时间点卡你
什么时候还能用?
- 非 UI 逻辑
- 低优先级副作用
- 日志 / 打点
二、debounce:减少执行次数,不是调度
代码
constdebouncedFilter=debounce((v)=>{setList(filter(data,v))},300)它解决的是什么?
“你别每次都算”
- 用户输入 10 次
- debounce 后只算 1 次
它没解决什么?
- 一旦真的执行
filter(data)仍然是同步的- 仍然会卡主线程
debounce = 减少次数,不是让 UI 优先
debounce 的适用场景
| 场景 | 是否合适 |
|---|---|
| 请求接口 | ✅ |
| 自动保存 | ✅ |
| 搜索接口 | ✅ |
| 本地大计算 | ❌ |
三、startTransition:React 级别的“让路”
代码
startTransition(()=>{setList(filter(data))})它到底做了什么?
React 在内部标记:
“这次更新可以被打断”
然后:
- 输入事件 → 高优先级
- transition 更新 → 低优先级
- React 在空闲时间切片执行
时间线对比(非常关键)
setTimeout / debounce
filter 开始 ↓ 500ms 主线程占满 ↓ 输入卡startTransition
filter 执行一部分 ↓ 用户输入 ↓ React 中断 filter ↓ 更新 input ↓ 继续 filter这是本质差异。
四、三者最容易搞混的一点
startTransition 不会减少计算量
filter(data)// 还是会算它只是:
- 不一次性算完
- 不阻塞 urgent 更新
五、正确的组合方式(生产级)
debounce + startTransition(最强)
constonChange=debounce((value)=>{startTransition(()=>{setList(filter(data,value))})},200)既少算,又不卡
错误组合(常见)
startTransition(()=>{debounce(()=>setList(...),300)()})完全没意义。
六、一个表格搜索的真实决策树
输入 → 表格过滤 → 10000 行
| 问题 | 答案 |
|---|---|
| 每次输入都要算吗? | ❌ |
| 能不能晚点算? | ✅ |
| 用户在 input 框输入必须立即显示文字吗? | ✅ |
debounce + startTransition
七、为什么 React 团队不推荐 setTimeout?
因为:
- 它绕过 React Scheduler
- React 无法协调更新
- 在 Concurrent 模式下是“黑盒”
八、用一句工程化标准帮你记住
JS 时间工具(setTimeout / debounce)
管“什么时候执行”React 工具(startTransition)
管“谁先执行”
九、最后一段“刻进脑子”的话
setTimeout:
“等会再卡你”debounce:
“少卡几次”startTransition:
“先让用户动起来”