requestIdleCallback 在移动端为什么不生效?
我在做一个移动端的长列表渲染优化,尝试用 requestIdleCallback 来分片处理数据,但在 iOS Safari 和部分安卓浏览器上完全没反应,回调根本不执行。查了下兼容性,难道真的一点办法都没有吗?
我试过加 polyfill,也用 setTimeout 降级了,但想搞清楚是不是我用法有问题。比如下面这段代码:
requestIdleCallback((deadline) => {
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
const task = tasks.shift();
processTask(task);
}
if (tasks.length > 0) {
requestIdleCallback(arguments.callee);
}
});
requestIdleCallback实现有 bug —— 它只有在主线程真正“空闲”时才触发回调,而移动端页面通常一直在做滚动、动画、JS 执行这些事,主线程根本“空”不下来,所以回调永远不执行。更坑的是,iOS 13 之前压根没实现这个 API,iOS 13+ 虽然有,但行为和 Chrome 差很多,经常卡住不回调,尤其在页面有滚动或动画时。
你那段代码逻辑没问题,但用
arguments.callee是个坏习惯,而且递归调用时没防抖或节流,容易把主线程又塞满。我现在的做法是:
- 优先用
requestIdleCallback,但加个兜底计时器- 每次调用前先判断下浏览器是否真的支持且“活”着(比如用一个 flag 标记上次回调是否执行)
- 分片时加个最小时间片(比如至少跑 1ms),避免频繁调度
下面这样写更清晰点:
另外提醒下,别用
arguments.callee,ES5 严格模式下直接报错,而且递归名明确点更利于调试。如果真要兼容 iOS 12 以下,建议直接上
setTimeout+performance.now()自己模拟 idle 行为,虽然丑点但稳。