2025 前端工程师必备:20 个零依赖、高性能的浏览器原生 API 全解析

48 阅读8分钟

1. ResizeObserver —— 监听 DOM 尺寸变化

🔍 作用

监听任意 DOM 元素的 content box(内容区域)宽高变化,比 window.onresize 更精准、高效。

🧩 完整示例

<div id="resizable" style="width: 200px; height: 100px; background: lightblue; resize: both; overflow: auto;">
  拖动右下角调整大小
</div>
<script>
  const target = document.getElementById('resizable');
  const ro = new ResizeObserver((entries) => {
    for (const entry of entries) {
      const { width, height } = entry.contentRect;
      console.log(`元素尺寸:${width} x ${height}`);
      // 可在此处触发图表重绘、布局调整等
    }
  });
  ro.observe(target);
</script>

📌 参数说明

  • entries: Array of ResizeObserverEntry
    • entry.target: 被观察的 DOM 元素
    • entry.contentRect: {x, y, width, height},等价于 getBoundingClientRect() 但不含 border/padding

⚠️ 注意

  • 不会因 CSS transform 触发
  • 避免在回调中修改被观察元素尺寸(可能引发无限循环)

🌐 兼容性

✅ Chrome 64+ | Firefox 69+ | Safari 13.1+ | Edge 79+


2. IntersectionObserver —— 检测元素是否进入视口

🔍 作用

异步检测目标元素与祖先容器(通常是 viewport)的交叉状态,用于懒加载、曝光统计等。

🧩 完整示例(图片懒加载)

<img data-src="https://example.com/image.jpg" class="lazy" alt="延迟加载">
<script>
  const images = document.querySelectorAll('.lazy');
  const io = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src; // 加载真实图片
        observer.unobserve(img);   // 加载后停止监听
      }
    });
  }, {
    root: null,          // 默认为 viewport
    rootMargin: '50px',  // 提前 50px 触发
    threshold: 0.01      // 只要 1% 进入视口就触发
  });

  images.forEach(img => io.observe(img));
</script>

📌 关键配置项

  • root: 容器元素(默认为浏览器视口)
  • rootMargin: 类似 CSS margin,扩展/收缩检测区域
  • threshold: 0~1 的数字或数组,表示交叉比例阈值

🌐 兼容性

✅ 所有现代浏览器(IE 不支持)


3. Page Visibility API —— 判断页面是否可见

🔍 作用

检测用户是否切换到其他标签页或最小化窗口。

🧩 完整示例

document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    console.log('页面已隐藏,暂停视频/轮询');
    // video.pause();
    // clearInterval(pollingInterval);
  } else {
    console.log('页面恢复可见,继续播放/轮询');
    // video.play();
  }
});

📌 属性

  • document.hidden: true 表示页面不可见
  • document.visibilityState: 'visible' | 'hidden' | 'prerender' | 'unloaded'

🌐 兼容性

✅ 所有浏览器(包括 IE10+)


4. Web Share API —— 调用系统分享面板

🔍 作用

唤起操作系统原生分享菜单(微信、微博、邮件等)

🧩 完整示例

<button id="shareBtn">分享本页</button>
<script>
  document.getElementById('shareBtn').addEventListener('click', async () => {
    if (!navigator.share) {
      alert('当前浏览器不支持 Web Share');
      return;
    }
    try {
      await navigator.share({
        title: document.title,
        text: '快来看这篇好文!',
        url: location.href
      });
    } catch (err) {
      console.warn('分享被取消或失败:', err);
    }
  });
</script>

⚠️ 限制

  • 必须在 HTTPS 环境下(localhost 除外)
  • 必须由 用户手势(如 click)触发
  • 桌面 Safari 支持有限

🌐 兼容性

✅ Android Chrome | iOS Safari 12.2+ | Windows Chrome(部分)


5. Wake Lock API —— 防止屏幕熄灭

🔍 作用

请求保持屏幕常亮(适用于阅读、直播、扫码等场景)

🧩 完整示例

<button id="lockBtn">保持屏幕常亮</button>
<script>
  let wakeLock = null;

  async function requestWakeLock() {
    try {
      wakeLock = await navigator.wakeLock.request('screen');
      console.log('Wake Lock 已激活');
      wakeLock.addEventListener('release', () => {
        console.log('Wake Lock 已释放');
      });
    } catch (err) {
      console.error('无法获取 Wake Lock:', err);
    }
  }

  document.getElementById('lockBtn').addEventListener('click', requestWakeLock);

  // 页面隐藏时自动释放(最佳实践)
  document.addEventListener('visibilitychange', () => {
    if (wakeLock !== null && document.hidden) {
      wakeLock.release().then(() => wakeLock = null);
    }
  });
</script>

⚠️ 限制

  • 必须 HTTPS + 用户手势
  • 仅支持 'screen' 类型(音频锁已被移除)
  • Safari 不支持

🌐 兼容性

✅ Chrome 84+ | Edge 84+ | ❌ Firefox / Safari


6. Broadcast Channel API —— 同源跨标签通信

🔍 作用

在同源(协议+域名+端口相同)的不同页面/iframe 间广播消息

🧩 完整示例(两个标签页同步登录状态)

// 所有页面都执行以下代码
const bc = new BroadcastChannel('auth-channel');

// 发送登录消息(例如登录成功后)
function login(username) {
  bc.postMessage({ type: 'login', user: username });
}

// 监听消息
bc.onmessage = (event) => {
  if (event.data.type === 'login') {
    alert(`其他页面已登录:${event.data.user}`);
    // 可刷新 UI 或跳转
  }
};

// 示例:点击按钮模拟登录
document.body.innerHTML += '<button onclick="login(\'Alice\')">模拟登录</button>';

📌 特点

  • 消息为结构化克隆(支持对象、数组等)
  • 不依赖 localStorage,无轮询开销

🌐 兼容性

✅ Chrome 54+ | Firefox 38+ | Edge 79+ | ❌ Safari(17+ 实验性支持)


7. PerformanceObserver —— 监听性能指标

🔍 作用

订阅浏览器性能条目(如 LCP、FCP、CLS),用于真实用户监控(RUM)

🧩 完整示例(上报 LCP)

function sendToAnalytics(metric) {
  console.log('上报性能指标:', metric.name, metric.startTime);
  // 实际项目中可发往 GA、自建监控系统等
}

const po = new PerformanceObserver((list) => {
  list.getEntries().forEach(sendToAnalytics);
});

// 监听 Largest Contentful Paint
po.observe({ type: 'largest-contentful-paint', buffered: true });
// 也可监听 'first-input', 'layout-shift', 'navigation' 等

📌 关键点

  • buffered: true:获取页面加载过程中已发生的指标
  • 需在 <head> 尽早注册,避免漏掉早期指标

🌐 兼容性

✅ 所有现代浏览器(Web Vitals 标准)


8. requestIdleCallback —— 在空闲时执行任务

🔍 作用

将低优先级任务(如日志、预加载)安排在浏览器空闲帧执行

🧩 完整示例

function logData(deadline) {
  // deadline.timeRemaining() 返回剩余空闲时间(毫秒)
  while (deadline.timeRemaining() > 0 || deadline.didTimeout) {
    if (tasks.length > 0) {
      const task = tasks.shift();
      processTask(task);
    } else {
      break;
    }
  }
  if (tasks.length > 0) {
    // 任务未完成,继续调度
    requestIdleCallback(logData);
  }
}

const tasks = ['task1', 'task2', 'task3'];
requestIdleCallback(logData, { timeout: 2000 }); // 最多等 2 秒

⚠️ 注意

  • Safari 不支持 → 可用 setTimeout(fn, 0) 降级
  • 已被 scheduler.postTask 逐步取代

🌐 兼容性

✅ Chrome 47+ | Firefox 55+ | ❌ Safari


9. scheduler.postTask —— 优先级任务调度(实验性)

🔍 作用

按优先级(user-blocking, user-visible, background)调度任务

🧩 完整示例

if ('scheduler' in window) {
  scheduler.postTask(() => {
    console.log('后台任务执行');
  }, { priority: 'background' });

  scheduler.postTask(() => {
    console.log('高优任务执行');
  }, { priority: 'user-blocking' });
} else {
  // 降级到 setTimeout
  setTimeout(() => console.log('降级执行'), 0);
}

🌐 兼容性

⚠️ 仅 Chrome 105+(需开启实验性 Web Platform features)


10. AbortController —— 统一取消异步操作

🔍 作用

提供标准方式取消 fetch、setTimeout、自定义 Promise 等

🧩 完整示例(取消 fetch)

const controller = new AbortController();
const { signal } = controller;

fetch('/api/data', { signal })
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('请求被取消');
    } else {
      console.error('请求失败:', err);
    }
  });

// 5 秒后自动取消
setTimeout(() => controller.abort(), 5000);

📌 通用模式

任何接受 signal 的 API 都可被取消(如 addEventListener({ signal })

🌐 兼容性

✅ 所有现代浏览器


11. ReadableStream —— 流式读取数据(如响应体)

🔍 作用

以流(stream)方式逐步读取数据,避免一次性加载大文件导致内存溢出。常用于处理 fetch 响应、实时日志、视频流等。

🧩 完整示例:逐块读取并显示文本

<button id="loadBtn">加载大文本</button>
<pre id="output" style="white-space: pre-wrap; max-height: 300px; overflow: auto;"></pre>

<script>
  document.getElementById('loadBtn').addEventListener('click', async () => {
    const output = document.getElementById('output');
    output.textContent = '正在加载...';

    try {
      // 模拟一个返回大文本的接口(需 CORS 支持)
      const response = await fetch('https://httpbin.org/stream-bytes/10000'); // 返回 10KB 随机字节

      if (!response.body) {
        throw new Error('ReadableStream not supported');
      }

      const reader = response.body.getReader();
      const decoder = new TextDecoder(); // 将 Uint8Array 转为字符串
      let receivedLength = 0;

      while (true) {
        const { done, value } = await reader.read(); // value 是 Uint8Array
        if (done) {
          output.textContent += '\n\n✅ 加载完成';
          break;
        }

        receivedLength += value.length;
        const chunk = decoder.decode(value, { stream: true }); // 流式解码
        output.textContent += chunk;

        // 可选:限制输出长度防卡顿
        if (receivedLength > 5000) {
          output.textContent += '\n...(仅展示前 5KB)';
          reader.cancel(); // 主动取消后续读取
          break;
        }
      }
    } catch (err) {
      console.error('流读取失败:', err);
      document.getElementById('output').textContent = '❌ 加载失败: ' + err.message;
    }
  });
</script>

📌 关键点

  • response.bodyReadableStream<Uint8Array>
  • reader.read() 返回 { done: boolean, value: Uint8Array }
  • 使用 TextDecoder({ stream: true }) 处理跨块字符(如中文)
  • 调用 reader.cancel() 可中断读取

⚠️ 注意

  • 不适用于 JSON API(因 JSON 需完整解析)
  • 适合文本、二进制、SSE(Server-Sent Events)等流式协议

🌐 兼容性

✅ Chrome 43+ | Firefox 65+ | Safari 10.1+ | Edge 79+


12. WritableStream —— 流式写入数据

🔍 作用

将数据分块写入目标(如文件、网络、内存),适用于上传、生成大文件、实时保存草稿等。

🧩 完整示例:创建可下载的流式文本文件

<button id="downloadBtn">生成并下载大文件</button>
<script>
  document.getElementById('downloadBtn').addEventListener('click', async () => {
    // 创建 WritableStream
    const writableStream = new WritableStream({
      start(controller) {
        console.log('WritableStream 启动');
      },
      write(chunk, controller) {
        console.log('写入块:', chunk);
        // 实际项目中可写入文件系统或网络
      },
      close() {
        console.log('流已关闭');
      },
      abort(reason) {
        console.error('流被中止:', reason);
      }
    });

    const writer = writableStream.getWriter();

    // 模拟分块写入
    for (let i = 0; i < 5; i++) {
      await writer.write(`Chunk ${i}\n`);
      await new Promise(r => setTimeout(r, 200)); // 模拟延迟
    }

    await writer.close();

    // 💡 实际应用:结合 File System Access API 写入本地文件(见第 14 项)
    alert('WritableStream 写入完成(控制台查看日志)');
  });
</script>

💡 真实场景:通常与 TransformStreamFile API 结合,例如:

const fileHandle = await window.showSaveFilePicker();
const writable = await fileHandle.createWritable();
// 然后通过 writable.write(chunk) 写入

🌐 兼容性

✅ Chrome 52+ | Firefox 102+ | Safari 14.1+ | Edge 79+


13. Background Fetch —— PWA 后台静默下载

🔍 作用

即使用户关闭页面,也能在后台下载大文件(如视频课程),支持断点续传。

🧩 完整示例(需 Service Worker)

⚠️ 此 API 必须在 Service Worker 中调用

1. 注册 SW(main.js)

// main.js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

2. Service Worker(sw.js)

// sw.js
self.addEventListener('backgroundfetchsuccess', (event) => {
  console.log('后台下载成功:', event.id);
  // 可通知用户或缓存到 Cache Storage
});

self.addEventListener('backgroundfetchfail', (event) => {
  console.error('后台下载失败:', event.id);
});

3. 触发下载(页面中)

// 页面 JS
document.getElementById('downloadVideo').addEventListener('click', async () => {
  const registration = await navigator.serviceWorker.ready;
  try {
    const bgFetch = await registration.backgroundFetch.fetch('course-video', [
      '/video1.mp4',
      '/video2.mp4'
    ], {
      title: '课程视频下载中...',
      icons: [{ src: '/icon.png', sizes: '128x128' }]
    });
    console.log('后台下载已启动:', bgFetch.id);
  } catch (err) {
    console.error('无法启动后台下载:', err);
  }
});

⚠️ 限制

  • 仅限 PWA 安装后使用
  • 必须 HTTPS
  • 用户需授权(首次会弹窗)
  • 目前 仅 Chrome/Edge 支持

🌐 兼容性

⚠️ Chrome 71+ | ❌ Firefox / Safari


14. File System Access API —— 读写本地真实文件

🔍 作用

让用户直接打开/保存本地文件(绕过 <input type="file"> 的沙盒限制),适用于 Web IDE、文档编辑器。

🧩 完整示例:打开文件 → 编辑 → 保存回原文件

<textarea id="editor" style="width:100%;height:200px;"></textarea><br>
<button id="openBtn">打开文件</button>
<button id="saveBtn">保存文件</button>

<script>
  let currentFileHandle = null;

  // 打开文件
  document.getElementById('openBtn').addEventListener('click', async () => {
    try {
      [currentFileHandle] = await window.showOpenFilePicker({
        types: [{
          description: '文本文件',
          accept: { 'text/plain': ['.txt'] }
        }],
        multiple: false
      });

      const file = await currentFileHandle.getFile();
      const contents = await file.text();
      document.getElementById('editor').value = contents;
    } catch (err) {
      if (err.name !== 'AbortError') console.error(err);
    }
  });

  // 保存文件
  document.getElementById('saveBtn').addEventListener('click', async () => {
    if (!currentFileHandle) {
      alert('请先打开一个文件');
      return;
    }

    const writable = await currentFileHandle.createWritable();
    await writable.write(document.getElementById('editor').value);
    await writable.close();
    alert('✅ 文件已保存!');
  });
</script>

⚠️ 安全限制

  • 必须由 用户手势(如点击)触发
  • 必须 HTTPS
  • 首次操作会弹出系统文件选择器(用户授权)

🌐 兼容性

✅ Chrome 86+ | Edge 86+ | ❌ Firefox / Safari(部分实验性)


15. Clipboard API —— 安全读写剪贴板

🔍 作用

异步读写剪贴板内容,替代不安全的 execCommand('copy')

🧩 完整示例

<input id="text" value="要复制的文本">
<button id="copyBtn">复制</button>
<button id="pasteBtn">粘贴</button>
<p id="result"></p>

<script>
  // 复制
  document.getElementById('copyBtn').addEventListener('click', async () => {
    try {
      await navigator.clipboard.writeText(document.getElementById('text').value);
      document.getElementById('result').textContent = '✅ 已复制到剪贴板';
    } catch (err) {
      console.error('复制失败:', err);
      document.getElementById('result').textContent = '❌ 复制失败,请检查权限';
    }
  });

  // 粘贴
  document.getElementById('pasteBtn').addEventListener('click', async () => {
    try {
      const text = await navigator.clipboard.readText();
      document.getElementById('result').textContent = '粘贴内容: ' + text;
    } catch (err) {
      console.error('粘贴失败:', err);
      document.getElementById('result').textContent = '❌ 无法读取剪贴板';
    }
  });
</script>

⚠️ 权限

  • 写入:只需用户手势(如 click)
  • 读取:部分浏览器要求额外权限(Chrome 会自动允许,Safari 可能弹窗)

🌐 兼容性

✅ Chrome 66+ | Firefox 63+ | Safari 13.1+ | Edge 79+


16. URLSearchParams —— 解析/构造 URL 查询参数

🔍 作用

无需正则,轻松操作 ?key=value&foo=bar 类型的查询字符串

🧩 完整示例

// 从当前 URL 解析
const params = new URLSearchParams(window.location.search);

// 获取参数
console.log(params.get('page')); // "2"

// 修改参数
params.set('page', '3');
params.append('tag', 'js');
params.delete('utm_source');

// 生成新 URL
const newUrl = `${window.location.pathname}?${params.toString()}`;
console.log(newUrl); // "/path?page=3&tag=js"

// 应用到历史记录(不刷新页面)
history.replaceState(null, '', newUrl);

📌 方法

  • .get(key) / .getAll(key)
  • .set(key, value) / .append(key, value)
  • .has(key) / .delete(key)
  • .toString()"key1=val1&key2=val2"

🌐 兼容性

✅ 所有现代浏览器(IE 不支持)


17. structuredClone() —— 原生深拷贝

🔍 作用

深度克隆对象,支持 Date、RegExp、Map、Set、ArrayBuffer、嵌套对象、循环引用等

🧩 完整示例

const original = {
  name: 'Alice',
  birth: new Date('1990-01-01'),
  tags: new Set(['dev', 'js']),
  meta: { count: 100 },
  self: null // 循环引用占位
};
original.self = original; // 创建循环引用

try {
  const copy = structuredClone(original);
  console.log(copy.name === original.name); // true(值相同)
  console.log(copy.birth !== original.birth); // true(新 Date 对象)
  console.log(copy.meta !== original.meta); // true(深拷贝)
  console.log(copy.self === copy); // true(循环引用正确保留)
} catch (err) {
  console.error('克隆失败:', err);
}

⚠️ 不支持类型

  • 函数(Function)
  • Symbol
  • DOM 节点
  • Proxy

🌐 兼容性

✅ Chrome 98+ | Firefox 94+ | Safari 15.4+ | Edge 98+

💡 降级方案:JSON.parse(JSON.stringify(obj))(但丢失函数/Date/undefined 等)


18. Intl.NumberFormat —— 国际化数字格式化

🔍 作用

按地区习惯格式化数字(货币、千分位、百分比等)

🧩 完整示例

const number = 1234567.89;

// 中文人民币
console.log(new Intl.NumberFormat('zh-CN', {
  style: 'currency',
  currency: 'CNY'
}).format(number)); // "¥1,234,567.89"

// 美元
console.log(new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(number)); // "$1,234,567.89"

// 百分比
console.log(new Intl.NumberFormat('en-US', {
  style: 'percent',
  minimumFractionDigits: 2
}).format(0.8765)); // "87.65%"

// 千分位(无单位)
console.log(new Intl.NumberFormat('de-DE').format(1234567)); // "1.234.567"

🌐 兼容性

✅ 所有现代浏览器(包括 IE11)


19. EyeDropper API —— 浏览器吸管工具

🔍 作用

调用系统级取色器,获取屏幕任意像素的 HEX 颜色值

🧩 完整示例

<button id="pickColor">吸取屏幕颜色</button>
<div id="colorBox" style="width:100px;height:100px;margin-top:10px;"></div>

<script>
  document.getElementById('pickColor').addEventListener('click', async () => {
    if (!window.EyeDropper) {
      alert('当前浏览器不支持 EyeDropper API');
      return;
    }

    try {
      const eyeDropper = new EyeDropper();
      const result = await eyeDropper.open(); // 用户点击后出现取色器
      document.getElementById('colorBox').style.backgroundColor = result.sRGBHex;
      console.log('选取的颜色:', result.sRGBHex);
    } catch (err) {
      if (err.name !== 'AbortError') console.error(err);
    }
  });
</script>

⚠️ 限制

  • 必须由用户手势触发
  • 仅返回 sRGB 格式(#RRGGBB)
  • 无法跨显示器/应用取色(仅限当前浏览器窗口)

🌐 兼容性

✅ Chrome 95+ | Edge 95+ | ❌ Firefox / Safari


20. WebCodecs API —— 原生音视频编解码

🔍 作用

直接访问硬件编解码器,实现低延迟、高性能视频处理(如 4K 60fps 播放、视频编辑)

🧩 完整示例:解码 VP9 视频帧并绘制到 Canvas

⚠️ 需要有效的视频流(此处仅为框架演示)

<canvas id="videoCanvas" width="640" height="360"></canvas>
<script>
  const canvas = document.getElementById('videoCanvas');
  const ctx = canvas.getContext('2d');

  const decoder = new VideoDecoder({
    output: (frame) => {
      // 将解码后的视频帧绘制到 canvas
      ctx.drawImage(frame, 0, 0);
      frame.close(); // 重要:释放帧内存
    },
    error: (e) => {
      console.error('解码错误:', e);
    }
  });

  // 配置解码器(需与视频编码匹配)
  decoder.configure({
    codec: 'vp09.00.10.08', // VP9 Profile 0
    codedWidth: 640,
    codedHeight: 360
  });

  // 模拟:从 ReadableStream 读取视频 chunk 并 enqueue
  // 实际项目中需从 fetch 或 MediaSource 获取
  // decoder.decode(chunk); // chunk 为 EncodedVideoChunk

  // 清理
  window.addEventListener('beforeunload', () => {
    decoder.close();
  });
</script>

📌 关键类

  • VideoDecoder / AudioDecoder
  • VideoEncoder / AudioEncoder
  • EncodedVideoChunk / EncodedAudioChunk

⚠️ 注意

  • 高级 API,适合音视频专业应用
  • 需处理大量底层细节(SPS/PPS、时间戳、关键帧等)

🌐 兼容性

✅ Chrome 94+ | Edge 94+ | ❌ Firefox / Safari


🎯 总结建议(2025 年实践指南)

推荐等级API 列表说明
🔥 强烈推荐ResizeObserver, IntersectionObserver, AbortController, URLSearchParams, Intl.NumberFormat, Clipboard高兼容、高实用、零成本
按需使用Page Visibility, Broadcast Channel, PerformanceObserver, structuredClone场景明确,现代项目常用
⚠️ 谨慎使用Wake Lock, EyeDropper, WebCodecs, File System Access, Background Fetch功能强大但兼容性有限,需降级方案

💡 最佳实践

  • 使用 Can I Use 检查目标用户浏览器支持情况
  • 对实验性 API 提供优雅降级(如 if ('wakeLock' in navigator)
  • 敏感 API(如文件、剪贴板)始终在用户手势后调用