💡 导语:Web 平台比大多数开发者想象的还要强大——而且每年,它都在悄悄地获得新的“超能力”。在日常开发中,我们已经习惯了遇到问题就去寻找第三方库。但事实上,随着 Web 标准的快速迭代,很多我们曾经依赖 npm 包来解决的问题,如今浏览器都已经原生支持了!如果你也喜欢探索浏览器的极限,今天这篇盘点绝对适合你。
以下这 10 个被严重低估的 Web API,有一些可能是你的“日常口粮”,但肯定有几个会让你惊呼:“等等,这玩意儿竟然是原生支持的?!” 😉
废话不多说,我们直接开始。
1. Structured Clone API (原生深拷贝)
我对这个 API 真是又爱又恨。多年来,我最喜欢问候选人的面试题之一就是:“如何深拷贝一个对象?”
从他们的回答中你能看出很多东西:
- 理解引用吗?
- 知道 Object.assign 和扩展运算符吗?
- 会用 JSON 黑科技吗?还是直接手写递归?
但现在,时代变了:
const copy = structuredClone(original);
就是这么简单直接。
💡 亮点:
- 支持 Map、Set、Date、Blob、File、ArrayBuffer 等复杂类型。
- 完美处理循环引用(再也不用担心 JSON.stringify 报错爆炸了 💥)。
兼容性: 现代浏览器(Chrome, Firefox, Safari, Edge)全覆盖,生产环境可放心使用。
2. Performance API (性能基准测试)
这是一个极度被低估的 API。
我们经常讨论性能,安装各种分析工具,跑 Lighthouse,争论哪种写法更好。但有时候你只需要确认一件事:“A 写法真的比 B 快吗,还是我属于过度优化?”
performance.mark("start");
// 这里放你需要测量性能的代码
performance.mark("end");
performance.measure("calc", "start", "end");
console.log(performance.getEntriesByName("calc"));
💡 适用场景:
- 微基准测试(Micro-benchmarks)。
- 验证 Web Worker 或 WASM 是否真的带来了提升。
- 打脸你的主观假设(因为有时候所谓“优化过”的代码其实跑得更慢 😅)。
3. Page Visibility API (页面可见性)
用来检测当前标签页是否处于激活状态。
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
video.pause(); // 切到后台时暂停视频
}
});
🗣️ 真实情况是: 用户打开了你的网页,然后切到别的标签页摸鱼 20 分钟……或者 2 小时……或者永远忘了它。
💡 适用场景:
- 暂停视频或复杂动画。
- 停止后台轮询请求。
- 降低 CPU 占用,拯救用户的电池。
兼容性: 所有现代浏览器均支持。用户的电池和你的后端服务器都会感谢你。
4. ResizeObserver (元素尺寸观察者)
终于,我们可以监听特定元素的尺寸变化了,而不仅仅是监听整个窗口 (window.resize)。
const ro = new ResizeObserver(entries => {
for (const entry of entries) {
console.log(entry.contentRect.width);
}
});
ro.observe(element);
如果你曾经开发过响应式组件、数据图表或复杂的 Dashboard,你肯定写过各种让人头疼的 resize 逻辑。
现在,这个 API 就像是浏览器在拍拍你的肩膀说:“放轻松,交给我吧。”
5. IntersectionObserver (交叉观察者)
ResizeObserver 的兄弟 API,用于检测一个元素是否进入了可视区域(Viewport)。
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("元素出现啦!");
}
});
});
io.observe(element);
💡 神级用处:
- 无限滚动(Infinite scroll)。
- 图片/组件懒加载。
- 触发滚动入场动画。
凡是手动写过 getBoundingClientRect 算滚动位置的人……试过这个之后绝对不想再退回去了 😄。
6. AbortController (万能中止控制器)
很多开发者知道它是用来取消 fetch 请求的,但它的作用远不止于此!
const controller = new AbortController();
fetch(url, { signal: controller.signal });
// 在需要的时候取消请求
controller.abort();
💡 进阶玩法: 你可以用同一个 signal 去取消多个操作,包括事件监听器、流操作或任何支持 Abort 接口的 API。
一次发出信号,优雅地清理多处逻辑,这让你的代码看起来非常“成熟且有可扩展性”。
7. Idle Detection API (空闲状态检测)
如果说 Page Visibility 告诉你“标签页”是否活跃,那 Idle Detection 就是告诉你**“屏幕前的人”**是否活跃。
const detector = new IdleDetector();
await detector.start();
detector.addEventListener("change", () => {
console.log(detector.userState); // active 或 idle
});
🗣️ 意味着: 用户的网页确实在前台开着,但他可能去泡咖啡了 ☕ 或者开会去了。
💡 适用场景:
- 敏感应用自动登出保护。
- 聊天软件自动切换“离开”状态。
感觉有点像在监视用户?确实,但真的很实用 😄。
注意: 目前主要在基于 Chromium 的浏览器中支持,且需要申请权限。
8. BroadcastChannel API (跨标签页通信神器)
实现多个标签页之间的轻松通信。
const channel = new BroadcastChannel("app_sync");
// 发送消息
channel.postMessage("logout");
// 接收消息
channel.onmessage = e => {
console.log("收到消息:", e.data);
};
💡 适用场景:
- 跨标签页同步登出(在一个页面退出,其他打开的页面自动退出)。
- 同步 Auth 状态、购物车数量等。
在用户习惯“以防万一打开 5 个标签页”的现实世界中,这个 API 异常实用。
9. Web Locks API (Web 分布式锁)
BroadcastChannel 的远房亲戚。防止多个标签页重复执行相同的工作。
navigator.locks.request("data-fetch-lock", async lock => {
// 只有获取到锁的标签页才会执行这里的逻辑
await fetchData();
});
💡 适用场景:
- 确保只有一个标签页去拉取增量通知。
- 避免多个页面同时向后端发送冗余的同步请求。
- 协调对本地 IndexedDB 等共享资源的读写。
这感觉简直就是“分布式系统概念杀入了前端”。(目前主要是 Chromium 阵营支持较好)
10. File System Access API (真·文件系统访问)
是的,你没看错——浏览器现在可以直接访问本地文件系统了。
// 唤起文件选择器
const [fileHandle] = await window.showOpenFilePicker();
// 获取真正的 File 对象
const file = await fileHandle.getFile();
💡 适用场景:
- 纯 Web 端的代码编辑器/文本编辑器。
- 复杂的本地文件导入/导出工具。
第一次使用这个 API 时,甚至会有一种“做黑客的错觉”:“我们在 Web 网页上真的被允许这么做吗?” 😄
🧠 最后的思考:回归平台
现代浏览器对这些 API 的支持度已经非常高了。尽管其中有些(如 Idle Detection, Web Locks, File System Access)目前还是 Chromium 偏科,上生产环境前务必查看一下 CanIUse。
但仅仅是**“知道它们的存在”**,就已经能让你在架构选型时占据优势。
Web 平台的发展速度令人惊叹。有时候,所谓的“新技术”并不是某个狂拽酷炫的新型 Framework,而是那些安静地躺在原生浏览器标准里的特性。
每次我们在终端敲下 npm install xxx 之前,不妨先停下来问问自己:“浏览器是不是早就把这事给办了?”
👉 互动话题:你最喜欢的、被严重低估的 Web API 是哪一个?欢迎在评论区分享你的看法!