前端 20 个零依赖浏览器原生 API 实战清单

1. ResizeObserver

ResizeObserver 用于监听元素的尺寸变化

简单来说:它能在元素的宽高变化时(包括内容撑开、CSS 改变、父容器变化等)自动触发回调。

1.1. 语法

javascript 复制代码
const observer = new ResizeObserver(entries => {
  for (let entry of entries) {
    console.log('元素尺寸变化了:')
    console.log('contentRect:', entry.contentRect)
    console.log('宽度:', entry.contentRect.width)
    console.log('高度:', entry.contentRect.height)
  }
})

observer.observe(document.querySelector('.box'))

参数说明:

  • entries:一个数组,每个元素是一个观察对象(ResizeObserverEntry)。
  • entry.contentRect:包含目标元素的内容区域大小。
  • observer.observe(el):开始观察某个元素。
  • observer.unobserve(el):停止观察某个元素。
  • observer.disconnect():断开所有观察。

1.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <title>ResizeObserver Demo</title>
    <style>
      .box {
        width: 200px;
        height: 100px;
        background-color: lightcoral;
        resize: both; /* 允许用户拖拽改变大小 */
        overflow: auto;
        padding: 10px;
      }
    </style>
  </head>
  <body>
    <div class="box">拖拽我改变大小</div>

    <script>
      const box = document.querySelector('.box')

      const observer = new ResizeObserver(entries => {
        for (let entry of entries) {
          console.log('新尺寸:', entry.contentRect.width, entry.contentRect.height)
        }
      })

      observer.observe(box)
    </script>
  </body>
</html>

1.3. 使用场景

  1. 自适应布局:元素大小变化时动态调整字体、图片尺寸等
  2. 图表组件:容器大小变化时重新渲染 Echarts、D3 图
  3. 动态内容:监控富文本内容区域变化触发滚动或对齐逻辑
  4. 虚拟滚动:当容器高度变化时重新计算可视区域范围
  5. 动画效果:元素尺寸发生变化触发动画或者过度效果

2. IntersectionObserver

IntersectionObserver 用来 监听元素是否进入(或离开)可视区域

它可以在不监听滚动事件、不计算位置的情况下,高效检测元素是否出现在视口中

2.1. 语法

javascript 复制代码
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('元素进入视口!', entry.target)
    } else {
      console.log('元素离开视口!', entry.target)
    }
  })
}, {
  root: null, // 观察的滚动容器,null 表示视口
  threshold: 0.1 // 触发回调的阈值(可见比例)
})

// 开始观察目标元素
observer.observe(document.querySelector('.box'))

参数说明:

  • entries:被观察元素的信息列表
  • entry.isIntersecting:元素是否进入可视区
  • entry.intersectionRatio:元素可见比例(0~1)
  • entry.target:当前被观察的 DOM 元素
  • root:可滚动容器(默认为浏览器视口)
  • threshold:元素可见比例达到多少触发(如 0.5 表示一半可见)

2.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>IntersectionObserver Demo</title>
    <style>
      body {
        margin: 0;
        font-family: sans-serif;
      }
      .spacer {
        height: 100vh; /* 模拟滚动空间 */
        background: #eee;
      }
      .box {
        width: 200px;
        height: 200px;
        margin: 100px auto;
        background-color: tomato;
        transition: transform 0.5s, opacity 0.5s;
        opacity: 0;
        transform: scale(0.8);
      }
      .visible {
        opacity: 1;
        transform: scale(1);
      }
    </style>
  </head>
  <body>
    <div class="spacer">向下滚动</div>
    <div class="box">观察我</div>
    <div class="spacer"></div>

    <script>
      const box = document.querySelector(".box");

      const observer = new IntersectionObserver(
        entries => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              box.classList.add("visible");
              console.log("进入可视区");
            } else {
              box.classList.remove("visible");
              console.log("离开可视区");
            }
          });
        },
        {
          threshold: 0.2, // 元素有20%可见时触发
        }
      );

      observer.observe(box);
    </script>
  </body>
</html>

2.3. 使用场景

  1. 图片懒加载:只有当图片进入视口时才加载真正的图片
  2. 无限滚动加载:页面滚动到底部时加载新数据
  3. 曝光埋点:广告或模块进入视口时统计曝光次数
  4. 动画触发:元素进入视口时触发淡入或淡出效果
  5. 页面定位:滚动时判断当前在哪个内容段落

3. Page Visibility

Page Visibility 用于判断网页当前是否在用户可见的状态

比如:

  • 用户切换到了其他页面
  • 用户最小化浏览器
  • 用户返回后重新看到当前页面

3.1. 语法

javascript 复制代码
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    console.log('页面隐藏了!')
  } else {
    console.log('页面可见了!')
  }
})

取值如下:

  • visible:页面当前可见(在前台)
  • hidden:页面不可见(被最小化或切换到其他标签页)
  • prerender:页面正在预渲染。

3.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <title>Page Visibility Demo</title>
  </head>
  <body>
    <h1>切换标签页看看控制台输出</h1>

    <script>
      document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'hidden') {
          console.log('页面隐藏了!')
        } else {
          console.log('页面可见了!')
        }
      })
    </script>
  </body>
</html>

3.3. 使用场景

  1. 视频播放优化:页面隐藏时暂停视频,返回后恢复播放
  2. 定时任务暂停:页面隐藏时暂停 setInterval 计时器
  3. 数据上报节省资源:页面隐藏时停止心跳或轮询请求
  4. 游戏性能优化:页面暂停时暂停动画、音效等逻辑
  5. 节能优化:减少 CPU 和内存消耗

4. Web Share

Web Share API 允许网页使用原生的分享界面(通常是手机系统的原生分享面板),用户可以把网页内容分享到其他应用。

简单来说:它让网页像 App 一样,可以"调用系统分享功能"。

4.1. 语法

javascript 复制代码
if (navigator.share) {
  navigator.share({
    title: '我的网站标题',
    text: '来看看这个网站!',
    url: 'https://example.com'
  })
    .then(() => console.log('分享成功'))
    .catch((err) => console.error('分享失败:', err));
} else {
  console.warn('当前浏览器不支持 Web Share API');
}

navigator.share() 的参数是一个对象,可以包含以下字段:

|---------|----------|------------------------|
| 字段 | 类型 | 说明 |
| title | string | 分享标题 |
| text | string | 分享文本 |
| url | string | 要分享的链接 |
| files | File[] | 可选,支持分享图片/视频文件(需HTTPS) |

4.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>原生 Web Share API 示例</title>
  </head>
  <body>
    <button id="shareBtn">分享当前页面</button>

    <script>
      const shareBtn = document.getElementById("shareBtn");

      shareBtn.addEventListener("click", async () => {
        if (navigator.share) {
          try {
            await navigator.share({
              title: document.title,
              text: "快来看看这个有趣的页面!",
              url: window.location.href,
            });
            console.log("用户已完成分享");
          } catch (err) {
            console.error("用户取消或分享失败:", err);
          }
        } else {
          alert("当前浏览器不支持 Web Share API");
        }
      });
    </script>
  </body>
</html>

5. Wake Lock

Wake Lock API(唤醒锁)可以防止设备因为"无操作"而自动关闭屏幕或进入休眠。目前主要支持屏幕唤醒锁(screen)。

5.1. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Wake Lock Demo</title>
  </head>
  <body>
    <h2>Wake Lock API 示例</h2>
    <button id="lockBtn">保持唤醒</button>
    <button id="unlockBtn">释放唤醒</button>

    <script>
      let wakeLock = null;

      // 请求唤醒锁
      async function requestWakeLock() {
        try {
          wakeLock = await navigator.wakeLock.request("screen");
          console.log("屏幕唤醒锁已启用");
          wakeLock.addEventListener("release", () => {
            console.log("唤醒锁已被释放");
          });
        } catch (err) {
          console.error("请求唤醒锁失败:", err);
        }
      }

      // 释放唤醒锁
      function releaseWakeLock() {
        if (wakeLock) {
          wakeLock.release();
          wakeLock = null;
        }
      }

      // 页面可见性变化时自动恢复锁(浏览器切出会自动失效)
      document.addEventListener("visibilitychange", () => {
        if (wakeLock !== null && document.visibilityState === "visible") {
          requestWakeLock();
        }
      });

      // 绑定按钮
      document.getElementById("lockBtn").addEventListener("click", requestWakeLock);
      document.getElementById("unlockBtn").addEventListener("click", releaseWakeLock);
    </script>
  </body>
</html>

讲解:

  • navigator.wakeLock.request('screen'):申请一个保持屏幕唤醒的锁
  • wakeLock.release():主动释放锁
  • wakeLock.addEventListener('release', ...):监听系统自动释放锁(比如切换标签页)
  • document.visibilitychange:当页面重新可见时重新请求锁(防止切出去回来实效)

5.2. 注意事项

  1. 只在 HTTPS 环境可用(或 localhost)
  2. 多数现代浏览器(如 Chrome、Edge、Android WebView)支持,IOS Safari 目前支持较差
  3. 必须在用户交互(点击按钮触发),否则会报错

5.3. 应用场景

  • 视频播放页面(防止看视频的时候屏幕黑掉)
  • 阅读器/在线文档
  • 导航类网页
  • 运动、计时类 Web App

6. BroadcastChannel

BroadcastChannel 允许在多个浏览器上下文(tab、iframe、web worker)直接进行消息广播。所有使用相同频道名(channel name)的页面都能互相通信

简单来说:它就像浏览器内的"广播电台"------所有收听同一个频道名的页面都能收到同样的消息。

6.1. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>BroadcastChannel Demo</title>
  </head>
  <body>
    <h2>🛰 BroadcastChannel 示例</h2>
    <input type="text" id="msgInput" placeholder="输入消息后回车广播" />
    <div id="log"></div>

    <script>
      // 1️. 创建频道(同名频道可以互相通信)
      const channel = new BroadcastChannel("chat-channel");
      const log = document.getElementById("log");

      // 2️. 接收来自其他页面的消息
      channel.onmessage = event => {
        const msg = event.data;
        log.innerHTML += `<p>收到消息:${msg}</p>`;
      };

      // 3️. 输入框发送消息
      document.getElementById("msgInput").addEventListener("change", e => {
        const message = e.target.value;
        channel.postMessage(message); // 广播给所有订阅此频道的页面
        e.target.value = "";
      });
    </script>
  </body>
</html>

API 详解

  • new BroadcastChannel(name):创建一个频道对象,参数时频道名(字符串)
  • channel.postMessage(data):向频道广播一条消息
  • channel.onmessage = handler:监听频道收到的消息
  • channel.close():关闭当前频道

6.2. 特点与限制

|------------|------------------------------|
| 特点 | 说明 |
| 实时通信 | 同源标签页、iframe、Web Worker 均可共享 |
| 同源限制 | 只能在相同协议 + 域名 + 端口的上下文间通信 |
| 不能跨浏览器 | 只在当前浏览器进程有效(不同浏览器或隐私模式之间不共享) |
| 生命周期短 | 页面关闭或 close() 后会自动失效 |

6.3. 应用场景

  1. 多标签页同步登陆状态:登陆或退出后,其他标签自动同步状态
  2. 多窗口聊天::多页面共享聊天内容
  3. 多标签页操作同步:设置项、主题切换实时同步
  4. 与 Web Worker 通信:主线程和 Worker 间广播状态变化

7. PerformanceObserver

PerformanceObserver用于监听性能事件(performance entries),这些是浏览器在运行过程中自动记录的,比如:

  • 页面加载阶段的指标(如 navigation)
  • 资源加载(如 resource)
  • 长任务(如 longtask)
  • 渲染阶段(如 paint)

简单理解:它是浏览器提供的**性能监听器,**可以实时获取数据而不需要手动打断点

7.1. 语法

javascript 复制代码
// 创建一个性能观察者
const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries()
  for (const entry of entries) {
    console.log('性能事件:', entry)
  }
})

// 监听的类型,比如资源加载、页面导航等
observer.observe({ type: 'resource', buffered: true })

7.2. 常见可观察类型

|------------------------------|-------------------------------|---------------------------------------------------------|
| 类型名 | 说明 | 示例字段 |
| 'resource' | 外部资源加载性能(CSS、JS、图片等) | entry.namedurationinitiatorType |
| 'navigation' | 页面加载性能(HTML 解析、DNS、TCP、DOM 等) | domContentLoadedEventEndloadEventEnd |
| 'paint' | 渲染阶段性能(首次绘制 FP、首次内容绘制 FCP) | entry.name = 'first-paint' / 'first-contentful-paint' |
| 'longtask' | 长任务检测(主线程卡顿 >50ms) | entry.duration |
| 'largest-contentful-paint' | 最大内容绘制(LCP) | 用于 Core Web Vitals |
| 'layout-shift' | 布局偏移(CLS) | entry.value 表示偏移量 |

7.3. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>PerformanceObserver Demo</title>
  </head>
  <body>
    <h1>性能观察 Demo</h1>
    <img src="https://picsum.photos/800/400" />

    <script>
      // 监听页面加载性能
      const perfObserver = new PerformanceObserver((list) => {
        list.getEntries().forEach(entry => {
          console.log(`[${entry.entryType}]`, entry.name, entry.duration)
        })
      })

      perfObserver.observe({ type: 'resource', buffered: true }) // 资源加载
      perfObserver.observe({ type: 'paint', buffered: true }) // 首次绘制
      perfObserver.observe({ type: 'navigation', buffered: true }) // 页面加载
    </script>
  </body>
</html>

7.4. 应用场景

  1. 页面加载性能监控:统计首屏加载时间、FCP、LCP
  2. 资源加载监控:判断哪些资源加载慢
  3. 性能上报:配合上报系统发送到后端分析
  4. 检测卡顿:使用'longtask'监控主线程阻塞
  5. 用户体验分析:跟踪 CLS(内容抖动)、FID(首次交互延迟)

**performance.getEntriesByType()**的区别?

performance.getEntriesByType('resource'):一次性获取当前已有的性能数据

performanceObserver:可以实时监听后续加载的性能数据(如懒加载图片)

前者是静态采样,后者是动态监听

8. requestIdleCallback

requestIdleCallback 会在浏览器"空闲"的时候调用你提供的回调函数。也就是说,当浏览器完成了渲染、用户交互、动画这些更重要的任务后,会在"有空"的时候来处理提交的低优先级任务。

8.1. 基本语法

javascript 复制代码
const handle = requestIdleCallback(callback[, options])
cancelIdleCallback(handle)

参数解释:

  • callback(deadline):空闲时执行的函数,接收一个 deadline 参数
  • options.timeout:超时时间(如果太久没有空闲出来也强制执行)
javascript 复制代码
requestIdleCallback(myTask, { timeout: 2000 })

deadline 对象解析

  • timeRemaining:返回当前帧剩余的空闲时间(毫秒)
  • dedTimeout:是否因超时被强制执行

8.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <title>requestIdleCallback Demo</title>
  </head>
  <body>
    <h2>requestIdleCallback 示例</h2>
    <p>打开控制台,看看浏览器"空闲"时才执行的任务。</p>

    <script>
      const tasks = Array.from({ length: 10 }, (_, i) => `任务 ${i + 1}`)

      function processTasks(deadline) {
        while (deadline.timeRemaining() > 0 && tasks.length > 0) {
          const task = tasks.shift()
          console.log(`执行:${task}`)
        }

        if (tasks.length > 0) {
          // 还有任务没完成,继续安排下一个空闲回调
          requestIdleCallback(processTasks)
        } else {
          console.log('所有任务完成')
        }
      }

      // 注册第一个空闲回调
      requestIdleCallback(processTasks)
    </script>
  </body>
</html>

运行效果:

浏览器在滚动、渲染、动画时不会执行任务,

当停止交互、主线程空闲时,控制台才逐个打印任务执行。

8.3. 使用场景

  1. 日志上报/埋点发送
  2. 缓存计算
  3. 非首屏数据预加载
  4. DOM 结构分析
  5. 离线缓存更新

9. scheduler.postTask

scheduler.postTask() 是一个 实验性的浏览器原生 API ,属于 Scheduler API 的一部分,用于更智能、更精细地调度任务执行。

它比 setTimeoutrequestIdleCallback 更强大,也更精确地控制任务优先级。

window.scheduler.postTask() 允许开发者将任务加入浏览器的调度队列中,并通过指定**优先级(priority)**来控制执行顺序。浏览器会跟据空闲情况与优先级智能的调度任务。

9.1. 语法

javascript 复制代码
scheduler.postTask(callback, options)

参数:

  • callback: 要执行的函数。
  • options: 一个配置对象,常用属性如下:
javascript 复制代码
{
  priority: 'user-blocking' | 'user-visible' | 'background',
  signal: AbortSignal // 可选,用于取消任务
}
  • 返回值:返回一个 Promise 对象,在任务执行后 resolve。

9.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>BroadcastChannel Demo</title>
  </head>
  <body>
    <button id="btn">执行任务</button>

    <script>
      document.getElementById("btn").addEventListener("click", async () => {
        console.log("主线程任务开始");

        await scheduler.postTask(
          () => {
            console.log("高优先级任务:用户交互相关");
          },
          {priority: "user-blocking"}
        );

        await scheduler.postTask(
          () => {
            console.log("中优先级任务:界面更新");
          },
          {priority: "user-visible"}
        );

        await scheduler.postTask(
          () => {
            console.log("低优先级任务:后台统计");
          },
          {priority: "background"}
        );

        console.log("主线程任务结束");
      });
    </script>
  </body>
</html>

9.3. 取消任务

javascript 复制代码
const controller = new AbortController();

scheduler.postTask(() => {
  console.log('执行前被取消');
}, { signal: controller.signal });

controller.abort(); // 任务不会执行

9.4. 兼容性与区别

目前仅 Chrome 94+ / Edge 94+ / Opera 80+ 支持。

Safari 和 Firefox 仍未实现。

setTimeout:延迟执行任务。

requestIdleCallback:在浏览器空闲时执行。

scheduler.postTask:有浏览器智能调度,支持优先级

10. AbortController

AbrotController 用于创建一个取消信号(signal),这个信号可以被多个信号异步操作监听,当你调用 .abrot()时,这些操作会立即停止。

10.1. 语法

javascript 复制代码
const controller = new AbortController();
const signal = controller.signal;
  • contoroller:控制器实例
  • signal:控制信号,用来传递"是否被取消"的状态

10.2. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>AbortController 请求取消示例</title>
  </head>
  <body>
    <button id="start">开始请求</button>
    <button id="cancel">取消请求</button>

    <script>
      let controller; // 保存控制器

      document.getElementById("start").addEventListener("click", () => {
        controller = new AbortController();
        const signal = controller.signal;

        console.log("开始发送请求...");

        // 这个接口会延迟 5 秒返回
        fetch("https://deelay.me/5000/https://jsonplaceholder.typicode.com/todos/1", {
          signal,
        })
          .then(res => res.json())
          .then(data => console.log("请求成功:", data))
          .catch(err => {
            if (err.name === "AbortError") {
              console.warn("请求被中止");
            } else {
              console.error("请求错误:", err);
            }
          });
      });

      document.getElementById("cancel").addEventListener("click", () => {
        if (controller) {
          controller.abort();
          console.log("已调用 abort()");
        }
      });
    </script>
  </body>
</html>

11. ReadableStream

ReadableStream 是浏览器中强大的 原生流式 API(Streaming API),用于按块(chunk)读取数据,而不是一次性加载整个资源

简单来说 ReadableStream 能按块读取网络或文件内容,而不是等到所有内容都下载完

11.1. 为什么需要它

假设你要请求一个 1GB 的视频或超长文本:

  • 普通 fetch()axios 必须等到 整个响应加载完 才能处理。
  • 有了 ReadableStream,你可以 边下载边处理(比如流式渲染、实时显示日志、逐步解析 JSON 等)。

11.2. 基本语法

javascript 复制代码
const reader = response.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  appendChunk(value);
}

概念:

  • ReadableStream:表示可读数据流(数据"源头")
  • getReader():获取流的读取器
  • read():每次读取一块数据 { done, value }
  • controller.enqueue():向流中添加数据
  • controller.close():关闭流
  • TextDecoder:把二进制转为字符串

11.3. 代码演示:ai 流式输出

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AI 流式输出 Demo</title>
    <style>
      body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
          Arial, sans-serif;
        background-color: #121212;
        color: #e0e0e0;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
      }
      .container {
        width: 80%;
        max-width: 700px;
        background-color: #1e1e1e;
        border-radius: 8px;
        padding: 2rem;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);
      }
      h1 {
        color: #bb86fc;
        text-align: center;
        margin-bottom: 2rem;
      }
      button {
        display: block;
        margin: 0 auto 2rem auto;
        padding: 10px 20px;
        font-size: 16px;
        cursor: pointer;
        background-color: #03dac6;
        color: #121212;
        border: none;
        border-radius: 4px;
        transition: background-color 0.3s;
      }
      button:hover {
        background-color: #018786;
      }
      #ai-output {
        background-color: #2c2c2c;
        border: 1px solid #444;
        border-radius: 4px;
        padding: 1rem;
        min-height: 200px;
        white-space: pre-wrap; /* 保持换行和空格 */
        line-height: 1.6;
        font-family: "Courier New", Courier, monospace;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>AI 流式输出 Demo</h1>
      <button id="startButton">向 AI 提问</button>
      <div id="ai-output"></div>
    </div>

    <script>
      // --- 1. 获取 DOM 元素 ---
      const startButton = document.getElementById("startButton");
      const outputElement = document.getElementById("ai-output");

      // --- 2. 预先定义好 AI 的完整回答 ---
      const fullText = `当然!ReadableStream 是一个强大的 Web API,它允许你以数据块(chunks)的形式顺序地处理一个大数据源,而无需一次性将所有数据加载到内存中。

它的核心优势在于:
1.  **内存高效**:无论源文件有多大,内存占用都极低。
2.  **响应迅速**:一旦接收到第一个数据块,就可以立即开始处理,提升用户体验。

这对于处理大文件下载、流式音视频播放等场景至关重要。`;

      // --- 3. 模拟流式输出的函数 ---
      function simulateAIStream(text, element) {
        // 清空之前的内容
        element.textContent = "";

        // 将完整文本拆分成单个字符的数组
        const chars = text.split("");
        let charIndex = 0;

        // 设置一个定时器,每 50 毫秒追加一个字符
        const streamInterval = setInterval(() => {
          // 检查是否还有字符需要显示
          if (charIndex < chars.length) {
            // 追加一个字符到元素的 textContent 中
            element.textContent += chars[charIndex];
            charIndex++;
          } else {
            // 如果所有字符都已显示,清除定时器
            clearInterval(streamInterval);
            console.log("流式输出完毕!");
          }
        }, 30); // 30毫秒的间隔,可以调整这个值来改变打字速度
      }

      // --- 4. 给按钮添加点击事件监听 ---
      startButton.addEventListener("click", () => {
        simulateAIStream(fullText, outputElement);
      });
    </script>
  </body>
</html>

11.4. 使用场景

  1. 大文件下载:边下载边显示进度
  2. AI/chatGPT 流式输出:模拟"字逐个出现"效果
  3. 实时日志流:实时打印服务器日志
  4. 流式 JSON 解析:大数据接口不必一次性解析

12. WritableStream

WritableStream 是用于以流的方式写入数据 。简单来说它可以逐步接受并处理数据,而不是等整个一次性加载完。

WritableStream 是浏览器原生提供的一个"写入管道",可以用来流式接收、处理或保存数据(而不是一次性加载完)。

一句话理解:

ReadableStream 是「读流」,
WritableStream 是「写流」。

当要把数据写入文件、网络请求、压缩器、转换器等目标时,就会用到WritableStream

12.1. 语法

javascript 复制代码
const writer = stream.writable.getWriter();
await writer.write(chunk);

概念:

  • ReadableStream:"可读流" → 数据来源
  • WritableStream:"可写流" → 数据接收
  • pipeTo():将可读流连接到可写流
  • getWriter():获取写入对象
  • write:写入数据块
  • close():结束流
  • abrot():中断写入

12.2. 代码演示

javascript 复制代码
const stream = new WritableStream({
  write(chunk) {
    console.log("写入数据:", chunk);
  },
  close() {
    console.log("写入完成");
  },
  abort(err) {
    console.error("写入被中止:", err);
  }
});

const writer = stream.getWriter();

writer.write("Hello");
writer.write("Stream");
writer.write("World");
writer.close();

12.3. 基本结构

javascript 复制代码
new WritableStream({
  start(controller) {
    // 初始化时调用
  },
  write(chunk, controller) {
    // 每次写入调用
  },
  close(controller) {
    // 流关闭时调用
  },
  abort(reason) {
    // 流出错或被取消时调用
  }
})

12.4. 典型应用场景

  1. 文件写入:使用 File System Access API 进行本地保存
  2. 大文件上传:分块上传(比如大文件断点续传)
  3. 数据管道(pipe):与 ReadableStream 结合,实现"流式复制"
  4. 实时处理数据:边读边写,比如数据转换、压缩、加密
  5. 逐块写入磁盘或网络
  6. 实时保存草稿

12.5. 示例:从 ReadableStream 管道写入 WritableStream

javascript 复制代码
const readable = new ReadableStream({
  start(controller) {
    ["A", "B", "C"].forEach(chunk => controller.enqueue(chunk));
    controller.close();
  },
});

const writable = new WritableStream({
  write(chunk) {
    console.log("接收到数据:", chunk);
  },
  close() {
    console.log("所有数据写入完成");
  },
});

// 管道连接:将 readable 的数据写入 writable
readable.pipeTo(writable);

12.6. 示例:写入文件(File System Access API)

javascript 复制代码
async function saveFile() {
  // 1. 用户选择保存位置
  const fileHandle = await window.showSaveFilePicker({
    suggestedName: "stream-demo.txt"
  });
  const writable = await fileHandle.createWritable();

  // 2. 通过 WritableStream 写入数据
  await writable.write("第一行\n");
  await writable.write("第二行\n");
  await writable.close();

  console.log("文件已保存!");
}

13. Background Fetch

Background Fetch(后台获取)API 可以让网页在关闭或切后台 时,仍然可以继续下载大文件(比如视频、离线包、游戏资源等)。

简单来说:Background Fetch 允许网页通过 Service Worker 在后台下载或上传大型文件,即使用户关闭了页面也不会中断任务

13.1. 为什么需要它

普通的 fetch() 请求在页面关闭后会被中断。

而如果是:

  • 要下载 超大视频/压缩包
  • 要上传大文件
  • 要在后台静默更新离线缓存

那么就需要 Bacnground Fetch。

13.2. 基本使用流程

javascript 复制代码
// 1️. 注册 Service Worker
navigator.serviceWorker.register('/sw.js');

// 2️. 在主线程中发起后台下载
const bgFetch = await registration.backgroundFetch.fetch(
  'video-download', // 下载任务的唯一标识
  ['/videos/big-video.mp4'], // 要下载的资源
  {
    title: '下载大视频中...',
    icons: [{ sizes: '72x72', src: '/icon.png', type: 'image/png' }],
    downloadTotal: 100 * 1024 * 1024 // 可选:预估文件大小(100MB)
  }
);

然后在 Service Worker 里监听事件

javascript 复制代码
// sw.js
self.addEventListener('backgroundfetchsuccess', event => {
  console.log('后台下载成功!');

  // 获取所有下载结果
  event.waitUntil(async function () {
    const records = await event.registration.matchAll();
    for (const record of records) {
      const response = await record.responseReady;
      const blob = await response.blob();
      // 保存文件或缓存
      console.log('保存文件:', blob.size, '字节');
    }
  }());
});

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

self.addEventListener('backgroundfetchabort', event => {
  console.log('下载被用户取消');
});

背景获取的事件生命周期 :

  • backgroundfetchclick:用户点击通知
  • backgroundfetchsuccess:下载全部成功
  • backgroundfetchfail:部分或全部失败
  • backgroundfetchabrot:用户取消下载

13.3. 应用场景

  1. 视频下载:用户离开页面时视频仍能继续缓存
  2. 离线应用更新:后台下载新版本资源包
  3. 大文件上传:用户切出页面后上传不被中断
  4. 后台通知:推送通知提醒用户

14. File System Access

File System Acess API 允许网页直接读取、写入和保存用户本地文件(需要用户授权)。这个 API 让 Web 应用拥有类似桌面应用的文件操作能力。

14.1. 语法

javascript 复制代码
const [fh] = await showOpenFilePicker();
editor.value = await (await fh.getFile()).text();

File System Access API 提供了几个核心接口:

  • showOpenFilePicker:打开文件选择器,获取文件句柄( FileSystemFileHandle )
  • showSaveFilePicker:打开文件保存对话框,获取保存文件的句柄
  • showDirectoryPicker:打开目录选择器,获取文件夹句柄( FileSystemDirectoryHandle )
  • FileSystemFileHandle:表示一个文件可以读取内容或写入内容
  • FileSystemWritableFileStream:写入流,用于将数据写入文件

14.2. 代码演示

14.2.1. 打开文件并读取内容
html 复制代码
<button id="open">打开文件</button>
  <pre id="output"></pre>

  <script>
  document.getElementById("open").addEventListener("click", async () => {
    try {
      // 打开文件选择器
      const [fileHandle] = await window.showOpenFilePicker();
      const file = await fileHandle.getFile();

      // 读取内容
      const content = await file.text();
      document.getElementById("output").textContent = content;
    } catch (err) {
      console.error("读取文件失败:", err);
    }
  });
</script>
14.2.2. 写入文件(保存内容)
html 复制代码
<button id="save">保存文件</button>

  <script>
  document.getElementById("save").addEventListener("click", async () => {
    try {
      // 打开保存文件对话框
      const handle = await window.showSaveFilePicker({
        suggestedName: "example.txt",
        types: [{
          description: "Text Files",
          accept: { "text/plain": [".txt"] },
        }],
      });

      // 创建写入流
      const writable = await handle.createWritable();
      await writable.write("这是写入的内容!");
      await writable.close();

      alert("文件已保存!");
    } catch (err) {
      console.error("写入文件失败:", err);
    }
  });
</script>
14.2.3. 读取文件夹中的多个文件
html 复制代码
<button id="openDir">选择文件夹</button>

  <script>
  document.getElementById("openDir").addEventListener("click", async () => {
    try {
      const dirHandle = await window.showDirectoryPicker();
      for await (const [name, handle] of dirHandle.entries()) {
        if (handle.kind === "file") {
          const file = await handle.getFile();
          console.log(`文件名: ${name}, 大小: ${file.size}`);
        }
      }
    } catch (err) {
      console.error("访问文件夹失败:", err);
    }
  });
</script>
14.2.4. 修改文件内容
javascript 复制代码
const [fileHandle] = await showOpenFilePicker();
const writable = await fileHandle.createWritable();
await writable.write("更新文件的新内容");
await writable.close();
14.2.5. 在线文本编辑器
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>文件系统访问 Demo - 在线编辑器</title>
  <style>
    body {
      font-family: "Microsoft YaHei", sans-serif;
      background: #f5f5f5;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: 30px;
    }
    h1 {
      color: #333;
    }
    .buttons {
      margin-bottom: 20px;
    }
    button {
      background: #0078d7;
      color: white;
      border: none;
      border-radius: 6px;
      padding: 10px 20px;
      margin: 0 5px;
      cursor: pointer;
      transition: background 0.3s;
    }
    button:hover {
      background: #005fa3;
    }
    textarea {
      width: 80%;
      height: 400px;
      font-size: 16px;
      padding: 10px;
      border-radius: 8px;
      border: 1px solid #ccc;
      resize: none;
      outline: none;
      background: #fff;
    }
  </style>
</head>
<body>
  <h1>在线文本编辑器</h1>
  <div class="buttons">
    <button id="openFile">打开文件</button>
    <button id="saveFile">保存文件</button>
  </div>
  <textarea id="editor" placeholder="在这里编辑文本..."></textarea>

  <script>
    let fileHandle = null; // 保存当前打开的文件句柄

    // 打开文件
    document.getElementById("openFile").addEventListener("click", async () => {
      try {
        const [handle] = await window.showOpenFilePicker({
          types: [
            {
              description: "文本文件",
              accept: { "text/plain": [".txt", ".md", ".json"] },
            },
          ],
        });
        fileHandle = handle;

        const file = await handle.getFile();
        const content = await file.text();
        document.getElementById("editor").value = content;
        alert(`已打开文件: ${file.name}`);
      } catch (err) {
        console.error("打开文件失败:", err);
      }
    });

    // 保存文件
    document.getElementById("saveFile").addEventListener("click", async () => {
      try {
        if (!fileHandle) {
          // 如果还没有文件句柄,就弹出保存窗口
          fileHandle = await window.showSaveFilePicker({
            suggestedName: "new-file.txt",
            types: [
              {
                description: "文本文件",
                accept: { "text/plain": [".txt", ".md", ".json"] },
              },
            ],
          });
        }

        const writable = await fileHandle.createWritable();
        await writable.write(document.getElementById("editor").value);
        await writable.close();
        alert("文件已保存!");
      } catch (err) {
        console.error("保存文件失败:", err);
      }
    });
  </script>
</body>
</html>

14.3. 总结

打开文件: showOpenFilePicker()

保存文件: showSaveFilePicker()

选择文件夹: showDirectoryPicker()

写文件:handle.createWritable()

读文件:handle.getFile()

15. Clipboard

Clipboard API 是浏览器原生提供的"复制/粘贴"能力。 可以用它 复制文本 / 图片到系统剪贴板 ,也可以 从剪贴板读取内容

15.1. 语法

javascript 复制代码
await navigator.clipboard.writeText('要复制的文字') //复制

await navigator.clipboard.readText()// 粘贴

15.2. 功能

|--------|---------------------------------------|------------------------|
| 功能 | 方法 | 说明 |
| 写入文本 | navigator.clipboard.writeText(text) | 把字符串复制到剪贴板 |
| 读取文本 | navigator.clipboard.readText() | 从剪贴板读取文本内容 |
| 写入多种类型 | navigator.clipboard.write(items) | 可写入图片、HTML 等 |
| 读取多种类型 | navigator.clipboard.read() | 可读取图片、HTML 等(需要 HTTPS) |

15.3. 代码演示

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>Clipboard API Demo</title>
    <style>
      body {
        font-family: "Microsoft YaHei", sans-serif;
        background: #f7f7f7;
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 50px;
      }
      h1 {
        color: #333;
      }
      textarea {
        width: 80%;
        height: 150px;
        margin: 10px 0;
        padding: 10px;
        font-size: 16px;
        border-radius: 6px;
        border: 1px solid #ccc;
        resize: none;
        outline: none;
      }
      button {
        background-color: #0078d7;
        color: white;
        border: none;
        padding: 10px 20px;
        border-radius: 6px;
        margin: 5px;
        cursor: pointer;
        transition: 0.2s;
      }
      button:hover {
        background-color: #005fa3;
      }
    </style>
  </head>

  <body>
    <h1>Clipboard API Demo</h1>

    <textarea id="inputText" placeholder="输入或粘贴内容..."></textarea>
    <div>
      <button id="copyBtn">复制到剪贴板</button>
      <button id="pasteBtn">从剪贴板粘贴</button>
    </div>

    <script>
      const input = document.getElementById("inputText");
      const copyBtn = document.getElementById("copyBtn");
      const pasteBtn = document.getElementById("pasteBtn");

      // 复制到剪贴板
      copyBtn.addEventListener("click", async () => {
        try {
          await navigator.clipboard.writeText(input.value);
          alert("已复制到剪贴板!");
        } catch (err) {
          alert("复制失败:" + err);
        }
      });

      // 从剪贴板读取
      pasteBtn.addEventListener("click", async () => {
        try {
          const text = await navigator.clipboard.readText();
          input.value = text;
          alert("已从剪贴板读取内容!");
        } catch (err) {
          alert("粘贴失败:" + err);
        }
      });
    </script>
  </body>
</html>

16. URLSearchParams

URLSearchParams 用于解析、构建和操作 URL 查询参数 (就是 ?key=value&key2=value2 那部分)

简单理解:URLSearchParams 就是一个可以帮你轻松读取和修改 URL 查询字符串的工具类

16.1. 基本语法

javascript 复制代码
const params = new URLSearchParams('?name=Tom&age=20')

16.2. 常用方法

|----------------------|---------|-----------------------------------------------|
| 方法 | 作用 | 示例 |
| get(key) | 获取参数值 | params.get('name') // "Tom" |
| set(key, value) | 修改或新增参数 | params.set('age', 25) |
| append(key, value) | 添加重复参数 | params.append('hobby', 'music') |
| delete(key) | 删除参数 | params.delete('age') |
| has(key) | 判断是否存在 | params.has('name') // true |
| toString() | 转成查询字符串 | params.toString() // "name=Tom&hobby=music" |

16.3. 代码演示

一句话总结:URLSearchParams 就是专门帮你读、改、拼接 URL 查询字符串的工具,比自己用正则拆字符串安全又简单。

16.3.1. 解析当前 URL 参数
javascript 复制代码
// 当前网址: https://example.com/?user=mingfei&role=admin
const params = new URLSearchParams(window.location.search)

console.log(params.get('user')) // mingfei
console.log(params.get('role')) // admin
16.3.2. 动态构建 URL
javascript 复制代码
const params = new URLSearchParams()
params.set('page', 2)
params.set('limit', 10)

const url = `https://api.example.com/users?${params.toString()}`
console.log(url)
// 输出: https://api.example.com/users?page=2&limit=10
16.3.3. 遍历所有参数
javascript 复制代码
const params = new URLSearchParams('?a=1&b=2&c=3')

for (const [key, value] of params) {
  console.log(key, value)
}
// 输出:
// a 1
// b 2
// c 3
16.3.4. 支持重复参数(数组场景)
javascript 复制代码
const params = new URLSearchParams()
params.append('tag', 'vue')
params.append('tag', 'javascript')

console.log(params.toString())
// tag=vue&tag=javascript

console.log(params.getAll('tag'))
// ['vue', 'javascript']
16.3.5. 合并参数
javascript 复制代码
const base = new URLSearchParams('a=1&b=2')
const extra = new URLSearchParams('b=3&c=4')

for (const [key, value] of extra) base.set(key, value)

console.log(base.toString()) // a=1&b=3&c=4

17. structuredClone

strycturedClone 用来实现深拷贝(deep clone)。

简单来说:structuredClone() 是浏览器原生提供的、用来安全复制任意 JS 对象的深拷贝函数,它支持 MapSetDateArrayBuffer 等复杂类型。

17.1. 语法

javascript 复制代码
const newObj = structuredClone(originalObj)
  • 参数:要克隆的对象
  • 返回值:一个全新的、与原对象完全独立的副本

17.2. 代码演示

javascript 复制代码
const user = {
  name: "Mingfei",
  info: { age: 22, hobby: ["Vue", "React"] },
}

const copy = structuredClone(user)

copy.info.age = 30
console.log(user.info.age) // 22 不受影响

这就是深拷贝:嵌套对象也会被完整复制。

17.3. 支持的类型

|----------------|----------|
| 类型 | 是否支持 |
| Object / Array | 是 |
| Date | 是 |
| RegExp | ❌否(会抛错) |
| Map / Set | 是 |
| TypedArray | 是 |
| ArrayBuffer | 是 |
| Blob / File | 是 |
| DOM Node | ❌ 否(会报错) |
| Function | ❌ 否(会报错) |

17.4. 与 JSON 方式的区别

|-------------------------|-----------------------------------|------------------------|
| 特性 | JSON.parse(JSON.stringify(obj)) | structuredClone(obj) |
| 深拷贝 | ✅ | ✅ |
| 支持循环引用 | ❌ | ✅ |
| 支持 MapSet | ❌ | ✅ |
| 支持 DateArrayBuffer | ❌ | ✅ |
| 丢失函数 | ✅ | ✅ |
| 性能 | 一般 | 更快且更安全 |

structuredClone() 是现代 JS 官方提供的"万能深拷贝神器",比 JSON 方案更安全、更快、更全面,支持复杂数据结构和循环引用。

18. Intl.NumberFormat

Intl.numberFormat 是一个非常使用的原生国际化(I18n) API。可以在不同语言、地区下自动格式化数字、货币、百分比等。

简单来说:Intl.NumberFormat 是 JavaScript 内置的国际化格式化工具,用来把数字根据语言与地区规则格式化成符合当地习惯的字符串。

18.1. 语法

javascript 复制代码
const formatter = new Intl.NumberFormat([locales], [options])
formatter.format(number)
  • locales:地区/语言代码,如 "zh-CN""en-US""ja-JP"
  • options:控制格式(货币、百分比、小数位数等)

18.2. 代码演示

18.2.1. 最简单的例子
javascript 复制代码
const num = 1234567.89

console.log(new Intl.NumberFormat().format(num))
// 在中文环境中输出:1,234,567.89

自动加上千位分隔符(,),不同语言下表现不同。

18.2.2. 格式化为货币
javascript 复制代码
const price = 1234.5

console.log(new Intl.NumberFormat('zh-CN', {
  style: 'currency',
  currency: 'CNY'
}).format(price))
// 输出:¥1,234.50

console.log(new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(price))
// 输出:$1,234.50

根据地区自动加货币符号,currency 支持 USDCNYJPYEUR 等。

18.2.3. 格式化百分比
javascript 复制代码
const ratio = 0.456

console.log(new Intl.NumberFormat('zh-CN', {
  style: 'percent',
  maximumFractionDigits: 1
}).format(ratio))
// 输出:45.6%
18.2.4. 指定最大小数位数
javascript 复制代码
const num = 1234.567

console.log(new Intl.NumberFormat('en-US', {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
}).format(num))
// 输出:1,234.57
18.2.5. 货币与数字混合控制
javascript 复制代码
const salary = 9876543.21

const formatter = new Intl.NumberFormat('de-DE', { // 德国
  style: 'currency',
  currency: 'EUR',
})

console.log(formatter.format(salary))
// 输出:9.876.543,21 €

注意:欧洲习惯用 . 做千分位,, 做小数点。

18.2.6. 紧凑显示(K/M/B)
javascript 复制代码
const views = 1234567

console.log(new Intl.NumberFormat('en', {
  notation: 'compact',
  compactDisplay: 'short'
}).format(views))
// 输出:1.2M

适合展示粉丝数、播放量、点赞数等场景。

18.3. 常用选项总结表

|-------------------------|------------------------------------------------------------|
| 选项 | 作用 |
| style | 'decimal' / 'currency / 'percent' / 'unit' |
| currency | 设置货币代码(如 'CNY''USD') |
| notation | 'standard' / 'scientific' / 'compact' |
| compactDisplay | 'short' / 'long'(配合 compact 使用) |
| minimumFractionDigits | 最少保留小数位 |
| maximumFractionDigits | 最多保留小数位 |
| unit | 'kilometer' / 'liter' / 'hour' 等(style 必须是 'unit') |

19. EyeDropper

EyeDropper 可以让用户在浏览器中取色(吸管工具) ,就像 Photoshop 或 Figma 那样。它是完全零依赖的浏览器原生能力。

19.1. 语法

javascript 复制代码
const eyeDropper = new EyeDropper();

eyeDropper.open()
  .then(result => {
    console.log(result.sRGBHex); // 输出颜色字符串,如 #1a2b3c
  })
  .catch(err => {
    console.error('用户取消或取色失败:', err);
  });

19.2. 代码演示

html 复制代码
<button id="pickColor">取色</button>
<div id="colorBox" style="width:100px; height:100px; border:1px solid #ccc;"></div>

<script>
  const btn = document.getElementById('pickColor');
  const box = document.getElementById('colorBox');

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

    try {
      const eyeDropper = new EyeDropper();
      const result = await eyeDropper.open(); // 打开取色工具
      box.style.backgroundColor = result.sRGBHex; // 显示取到的颜色
      console.log('取到的颜色:', result.sRGBHex);
    } catch (err) {
      console.log('用户取消取色或出错', err);
    }
  });
</script>

20. WebCodecs

WebCodes 它能让你直接访问浏览器底层的视频/音频编解码器(Codec),无需 ffmpeg、无需插件。

20.1. WebCOdecs 是什么

WebCodecs API 是一个底层多媒体编解码接口,允许 JavaScript 高效地:

  • 解码(decode) 视频或音频帧(比如 mp4、webm)
  • 编码(encode) 视频或音频帧(比如生成 webm 文件)
  • 在不经过 **

它为浏览器多媒体处理提供了近乎原生的性能

20.2. 语法

javascript 复制代码
const decoder = new VideoDecoder({
  output: frame => ctx.drawImage(frame, 0, 0),
  error: console.error
});
decoder.configure({ codec: 'vp09.00.10.08' });

20.3. 基本组成

WebCodecs 主要由以下几个核心类组成:

|---------------------|----------------------------------|
| 类名 | 功能 |
| VideoDecoder | 将压缩视频数据(如 H.264)解码为 VideoFrame |
| VideoEncoder | 将 VideoFrame 编码为压缩格式 |
| AudioDecoder | 解码音频 |
| AudioEncoder | 编码音频 |
| VideoFrame | 视频帧对象,可直接绘制到 <canvas> |
| EncodedVideoChunk | 压缩后的视频片段 |

20.4. 代码演示

20.4.1. 最基本的使用示例:解码视频帧
javascript 复制代码
// 1️. 创建视频解码器
const decoder = new VideoDecoder({
  output: handleFrame, // 每当解码出一帧时触发
  error: (e) => console.error("解码错误:", e)
});

// 2️. 配置解码器
decoder.configure({
  codec: 'vp8', // 支持: vp8, vp9, avc1 (H.264), av01, 等
});

// 3️. 模拟输入压缩视频数据
const chunk = new EncodedVideoChunk({
  type: "key", // 关键帧或 delta 帧
  timestamp: 0,
  data: new Uint8Array([/* 视频数据字节流 */])
});

// 4️. 输入视频数据进行解码
decoder.decode(chunk);

// 5️. 每帧输出回调
function handleFrame(frame) {
  console.log("解码到视频帧:", frame);
  // 可以直接绘制到 canvas
  const canvas = document.querySelector("canvas");
  const ctx = canvas.getContext("2d");
  ctx.drawImage(frame, 0, 0);
  frame.close(); // 必须手动释放内存
}
20.4.2. 编码示例:生成视频数据
javascript 复制代码
const encoder = new VideoEncoder({
  output: (chunk) => console.log("编码完成片段:", chunk),
  error: (e) => console.error(e),
});

encoder.configure({
  codec: 'vp8',
  width: 640,
  height: 480,
  bitrate: 1_000_000,
  framerate: 30,
});

// 用 Canvas 创建一帧
const canvas = document.createElement("canvas");
canvas.width = 640;
canvas.height = 480;
const ctx = canvas.getContext("2d");
ctx.fillStyle = "skyblue";
ctx.fillRect(0, 0, 640, 480);

// 将 Canvas 转成 VideoFrame
const frame = new VideoFrame(canvas, { timestamp: 0 });

// 编码该帧
encoder.encode(frame);
frame.close();

20.5. 性能优势

  • 直接使用系统硬件编解码器(GPU 加速);
  • 无需引入庞大的 ffmpeg.js;
  • 延迟极低,可用于实时视频流、虚拟会议、游戏录制等。

20.6. 应用场景

  1. 视频会议:低延迟推流、实时解码。
  2. 在线录屏:实时采集和编码
  3. 视频编辑器:本地转码、剪辑
  4. WebRTC 优化:自定义流处理前后端传输
  5. AI 视频分析:解码帧后传入 WebGPU/WebGL
相关推荐
文韬_武略3 小时前
web vue之状态管理Pinia
前端·javascript·vue.js
董世昌413 小时前
js怎样改变元素的内容、属性、样式?
开发语言·javascript·ecmascript
mosen8683 小时前
【Vue】Vue Router4x关于router-view,transtion,keepalive嵌套写法报错
前端·javascript·vue.js
鸠摩智首席音效师4 小时前
如何清除 Yarn 缓存 ?
javascript
写不来代码的草莓熊4 小时前
vue前端面试题——记录一次面试当中遇到的题(5)
前端
weixin_ab4 小时前
【HTML分离术】
前端·html
文心快码BaiduComate4 小时前
新手该如何选择AI编程工具?文心快码Comate全方位体验
前端·后端·程序员
夫唯不争,故无尤也4 小时前
Tomcat 内嵌启动时找不到 Web 应用的路径
java·前端·tomcat
lichong9514 小时前
【Xcode】Macos p12 证书过期时间查看
前端·ide·macos·证书·xcode·大前端·大前端++