🔍浏览器隐藏的 API,90% 前端没用过,却能让页面飞起

浏览器每帧 16.67 ms,渲染之外常有"垃圾时间";

如何把埋点、预加载、长计算悄悄塞进这段空隙,而不卡动画?
requestIdleCallback 就是答案。


一、它到底是啥?

js 复制代码
const id = requestIdleCallback(callback, { timeout: 1000 });
// id 用于 cancelIdleCallback(id);
  • 作用 :把低优先级任务 排队,等浏览器主线程空闲时再执行。
  • 返回 :任务 id,可 cancelIdleCallback(id) 取消。
  • 兼容性:Chrome 47+、Edge 16+、Safari 14+;Firefox 55+。

二、API 速记

参数 说明
callback 函数,接收 IdleDeadline 对象
options.timeout 最大等待毫秒,超时后强制执行

IdleDeadline 属性

  • timeRemaining():当前帧剩余时间(通常 0--50 ms)
  • didTimeout:是否因超时被触发

三、4 个可直接复制的实战场景

① 日志批量上报(不卡交互)

js 复制代码
const logs = [];
function track(e) { logs.push(e); scheduleFlush(); }

let flushPending = false;
function scheduleFlush() {
  if (flushPending) return;
  flushPending = true;
  requestIdleCallback(flushLogs, { timeout: 2000 });
}

function flushLogs(deadline) {
  while (logs.length && deadline.timeRemaining() > 2) {
    sendBatch(logs.splice(0, 5));
  }
  if (logs.length) requestIdleCallback(flushLogs, { timeout: 2000 });
  else flushPending = false;
}

用户点击、滑动时日志先缓存,空闲时再上报 。


② 预加载低优先级资源

js 复制代码
const lowRes = [
  '/img/banner-2.jpg',
  '/fonts/optional.woff2',
  '/data/suggestions.json'
];

function prefetchOnIdle() {
  let idx = 0;
  function next(deadline) {
    while (idx < lowRes.length && deadline.timeRemaining() > 0) {
      const link = document.createElement('link');
      link.rel = 'prefetch';
      link.href = lowRes[idx++];
      document.head.appendChild(link);
    }
    if (idx < lowRes.length) requestIdleCallback(next);
  }
  requestIdleCallback(next);
}
prefetchOnIdle();

首屏渲染完成后再偷偷加载后续资源,提升后续页面速度 。


③ 大数据分片计算(不阻塞主线程)

js 复制代码
function processLargeData(data, chunkSize) {
  let offset = 0;
  function processChunk(deadline) {
    const start = performance.now();
    while (offset < data.length && deadline.timeRemaining() > 0) {
      processSlice(data.slice(offset, offset += chunkSize));
    }
    if (offset < data.length) requestIdleCallback(processChunk);
    else console.log('✅ 处理完成');
  }
  requestIdleCallback(processChunk);
}

10 万条数据拆片,在主线程空闲时逐步处理 。


④ 计算 π 的蒙特卡洛方法(示例)

html 复制代码
<button onclick="start()">开始计算</button>
<button onclick="stop()">停止</button>
<div id="pi">等待开始...</div>
<script>
  let id, inside = 0, total = 0;
  function step() {
    const r = 10, x = Math.random() * 2 * r - r, y = Math.random() * 2 * r - r;
    if (x * x + y * y < r * r) inside++;
    total++;
    document.getElementById('pi').textContent = (4 * inside / total).toFixed(6);
  }
  function work(deadline) {
    while (deadline.timeRemaining() > 0) step();
    id = requestIdleCallback(work);
  }
  function start() { id = requestIdleCallback(work); }
  function stop() { cancelIdleCallback(id); }
</script>

每帧有剩余时间就计算一步,不卡顿动画 。


四、不适合的场景

场景 原因
操作 DOM/更新 UI 当前帧已绘制,改 DOM 会强制重排
长耗时任务 > 50 ms 仍占主线程,需拆分或放 Worker
紧急任务(输入/动画) 应使用 requestAnimationFrame

五、一句话总结

requestIdleCallback = 主线程垃圾时间调度器 :把埋点、预加载、长计算塞进空闲帧,零阻塞、零依赖、零配置

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
晨米酱1 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄1 天前
JavaScript 隐式全局变量解析
javascript
彧azz1 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
汉堡大王95271 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端