每天一个高级前端知识 - Day 11

1 阅读3分钟

每天一个高级前端知识 - Day 11

今日主题:浏览器API深度挖掘 - 20个你不知道的现代浏览器超能力

核心概念:浏览器远比我们想象的要强大

很多强大API被主流框架的光芒掩盖,掌握它们能在不引入第三方库的情况下解决复杂问题。

🔍 第一类:性能与监控

1. PerformanceObserver - 监听性能事件

// 监听LCP (Largest Contentful Paint)
const lcpObserver = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];
  console.log('LCP:', lastEntry.renderTime || lastEntry.loadTime);
});
lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });

// 监听长任务(阻塞主线程超过50ms)
const longTaskObserver = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.warn(`长任务检测: ${entry.duration}ms`, entry);
    // 上报到监控系统
  }
});
longTaskObserver.observe({ type: 'longtask', buffered: true });

// 监听布局偏移(CLS)
const clsObserver = new PerformanceObserver((list) => {
  let clsValue = 0;
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      clsValue += entry.value;
    }
  }
  console.log('CLS:', clsValue);
});
clsObserver.observe({ type: 'layout-shift', buffered: true });

2. scheduler.yield() - 主动让出主线程

// 处理大数据不卡顿
async function processLargeData(data) {
  const chunkSize = 100;
  
  for (let i = 0; i < data.length; i += chunkSize) {
    const chunk = data.slice(i, i + chunkSize);
    
    // 处理当前块
    chunk.forEach(item => heavyComputation(item));
    
    // 让出主线程,让用户交互和渲染有机会执行
    await scheduler.yield();
  }
}

// 优先级任务调度
scheduler.postTask(() => {
  console.log('高优先级任务');
}, { priority: 'user-blocking' });

scheduler.postTask(() => {
  console.log('低优先级任务');
}, { priority: 'background' });

3. PerformanceMark - 自定义性能标记

// 标记性能边界
performance.mark('render-start');
await renderComponent();
performance.mark('render-end');
performance.measure('render-duration', 'render-start', 'render-end');

// 自动上报
const measure = performance.getEntriesByName('render-duration')[0];
console.log(`渲染耗时: ${measure.duration}ms`);

// 清理标记
performance.clearMarks();
performance.clearMeasures();

🎨 第二类:UI与交互

4. View Transitions API - 原生动画过渡

// SPA页面切换动画
function navigateToNewPage(url) {
  // 检查浏览器支持
  if (!document.startViewTransition) {
    updateDOM(url);
    return;
  }
  
  // 自动捕获前后快照,执行过渡动画
  document.startViewTransition(() => {
    updateDOM(url);
  });
}

// 自定义过渡动画
document.startViewTransition({
  update: () => updateDOM(),
  types: ['slide-in'] // 指定过渡类型
});

// CSS中定义不同过渡效果
::view-transition-old(slide-in) {
  animation: slide-out 0.3s ease;
}
::view-transition-new(slide-in) {
  animation: slide-in 0.3s ease;
}

5. Popover API - 原生弹窗

<!-- 不需要JS的原生弹窗 -->
<button popovertarget="my-popover">打开弹窗</button>
<div id="my-popover" popover>
  <h3>原生弹窗标题</h3>
  <p>这是原生popover内容</p>
  <button popovertarget="my-popover" popovertargetaction="hide">关闭</button>
</div>

<!-- 悬停触发 -->
<button popovertarget="hover-popover" popovertargetaction="show">
  悬停显示
</button>
<div id="hover-popover" popover="hover">
  鼠标悬停时显示的内容
</div>
// 程序化控制
const popover = document.getElementById('my-popover');
popover.showPopover();    // 显示
popover.hidePopover();    // 隐藏
popover.togglePopover();  // 切换

// 监听事件
popover.addEventListener('beforetoggle', (e) => {
  console.log(e.newState === 'open' ? '即将打开' : '即将关闭');
});

6. CSS Scroll Snap - 滚动捕捉

/* 横向轮播 */
.scroll-container {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

.scroll-item {
  scroll-snap-align: start;
  scroll-snap-stop: always; /* 强制停靠 */
  flex: 0 0 100%;
}

/* 垂直滚动分页 */
.pagination-container {
  scroll-snap-type: y proximity; /* proximity更宽松 */
}

/* 子元素不同停靠位置 */
.item:first-child {
  scroll-snap-align: start;
}
.item:last-child {
  scroll-snap-align: end;
}

💾 第三类:存储与数据

7. File System Access API - 读写本地文件

// 打开文件
async function openFile() {
  const [fileHandle] = await window.showOpenFilePicker({
    types: [{
      description: '文本文件',
      accept: { 'text/plain': ['.txt', '.md'] }
    }],
    multiple: false
  });
  
  const file = await fileHandle.getFile();
  const content = await file.text();
  return content;
}

// 保存文件
async function saveFile(content) {
  const handle = await window.showSaveFilePicker({
    suggestedName: 'document.txt',
    types: [{
      description: '文本文件',
      accept: { 'text/plain': ['.txt'] }
    }]
  });
  
  const writable = await handle.createWritable();
  await writable.write(content);
  await writable.close();
}

// 读写目录
async function readDirectory() {
  const dirHandle = await window.showDirectoryPicker();
  
  for await (const entry of dirHandle.values()) {
    if (entry.kind === 'file') {
      const file = await entry.getFile();
      console.log(file.name, file.size);
    }
  }
}

8. Origin Private File System - 私有文件系统

// 存储大量应用数据(无大小限制)
const root = await navigator.storage.getDirectory();

// 创建文件
const fileHandle = await root.getFileHandle('data.json', { create: true });
const writable = await fileHandle.createWritable();
await writable.write(JSON.stringify({ data: 'important' }));
await writable.close();

// 读取文件
const file = await fileHandle.getFile();
const content = JSON.parse(await file.text());

// 创建目录
const dirHandle = await root.getDirectoryHandle('images', { create: true });
const imageHandle = await dirHandle.getFileHandle('photo.jpg', { create: true });

// 清空存储
await navigator.storage.estimate(); // 查看使用情况
await navigator.storage.persist();   // 请求持久化存储

🎯 第四类:设备能力

9. EyeDropper API - 取色器

const eyeDropper = new EyeDropper();

async function pickColor() {
  try {
    const result = await eyeDropper.open();
    console.log('选中的颜色:', result.sRGBHex);
    document.body.style.backgroundColor = result.sRGBHex;
  } catch (err) {
    console.error('取色失败:', err);
  }
}

// 配合剪贴板使用
async function pickAndCopy() {
  const result = await eyeDropper.open();
  await navigator.clipboard.writeText(result.sRGBHex);
  alert('颜色已复制: ' + result.sRGBHex);
}

10. Virtual Keyboard API - 虚拟键盘控制

// 移动端表单优化
const input = document.querySelector('input');

input.addEventListener('focus', () => {
  // 控制虚拟键盘行为
  if ('virtualKeyboard' in navigator) {
    navigator.virtualKeyboard.overlaysContent = true;
    // 键盘弹出时调整布局
    navigator.virtualKeyboard.addEventListener('geometrychange', (e) => {
      const { height, width } = e.target.boundingRect;
      document.body.style.paddingBottom = `${height}px`;
    });
  }
});

// HTML方式控制
<input virtualkeyboardpolicy="manual" /> <!-- 手动控制键盘 -->

11. Badging API - 应用角标

// 设置未读消息数量
function updateUnreadCount(count) {
  if ('setAppBadge' in navigator) {
    if (count > 0) {
      navigator.setAppBadge(count);
    } else {
      navigator.clearAppBadge();
    }
  }
}

// 通知消息时更新角标
new Notification('新消息', { body: '您有3条未读消息' });
updateUnreadCount(3);

🔐 第五类:安全与认证

12. Web Authentication API - 生物识别

// 注册生物识别凭证
async function registerBiometric() {
  const publicKeyCredential = await navigator.credentials.create({
    publicKey: {
      challenge: new Uint8Array(32),
      rp: { name: "My App" },
      user: {
        id: new Uint8Array(16),
        name: "user@example.com",
        displayName: "User"
      },
      pubKeyCredParams: [{ alg: -7, type: "public-key" }],
      authenticatorSelection: {
        authenticatorAttachment: "platform", // 平台认证器(指纹/面容)
        userVerification: "required"
      }
    }
  });
  
  // 存储凭证ID供后续登录
  localStorage.setItem('credentialId', 
    btoa(String.fromCharCode(...new Uint8Array(publicKeyCredential.rawId))));
}

// 生物识别登录
async function loginWithBiometric() {
  const credentialId = localStorage.getItem('credentialId');
  const allowCredentials = [{
    id: Uint8Array.from(atob(credentialId), c => c.charCodeAt(0)),
    type: 'public-key'
  }];
  
  const assertion = await navigator.credentials.get({
    publicKey: {
      challenge: new Uint8Array(32),
      allowCredentials,
      userVerification: "required"
    }
  });
  
  console.log('生物识别验证成功!');
  // 执行登录逻辑
}

13. Permissions API - 精细化权限管理

// 查询权限状态
async function checkPermission(permission) {
  const result = await navigator.permissions.query({ name: permission });
  console.log(`${permission}权限:`, result.state); // 'granted', 'denied', 'prompt'
  
  result.addEventListener('change', () => {
    console.log(`${permission}权限变更为:`, result.state);
  });
  
  return result.state;
}

// 检查多种权限
await checkPermission('geolocation');
await checkPermission('notifications');
await checkPermission('camera');
await checkPermission('microphone');
await checkPermission('clipboard-read');

// 检查存储持久化权限
const persisted = await navigator.storage.persisted();
if (!persisted) {
  const granted = await navigator.storage.persist();
  console.log('持久化存储授权:', granted);
}

📡 第六类:网络与通信

14. WebTransport API - 低延迟双向通信

// WebTransport: UDP-like但可靠,比WebSocket更快
const transport = new WebTransport('https://example.com:4433');

await transport.ready;

// 发送数据(无序,低延迟)
const writer = transport.datagrams.writable.getWriter();
writer.write(new Uint8Array([1, 2, 3, 4]));

// 接收数据
const reader = transport.datagrams.readable.getReader();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log('收到数据:', value);
}

// 可靠流(有序传输)
const stream = await transport.createBidirectionalStream();
const streamWriter = stream.writable.getWriter();
const streamReader = stream.readable.getReader();

15. Network Information API - 网络质量感知

// 获取网络信息
const connection = navigator.connection || navigator.mozConnection;
console.log({
  有效带宽: connection.downlink + 'Mbps',
  RTT: connection.rtt + 'ms',
  网络类型: connection.effectiveType, // 'slow-2g', '2g', '3g', '4g'
  节省数据模式: connection.saveData
});

// 根据网络质量调整内容
connection.addEventListener('change', () => {
  if (connection.saveData || connection.effectiveType === 'slow-2g') {
    // 低质量模式:加载低分辨率图片,减少请求
    loadLowQualityImages();
  } else if (connection.effectiveType === '4g') {
    // 高质量模式
    loadHighQualityImages();
  }
});

🎯 今日挑战

实现一个浏览器性能监控仪表板,要求:

  1. 实时监控LCP、FID、CLS等核心Web指标
  2. 监控长任务并可视化
  3. 显示网络状态(带宽、RTT)
  4. 存储监控数据到IndexedDB(使用私有文件系统)
  5. 提供导出报告功能(使用File System Access API)
// 使用示例
const monitor = new PerformanceMonitor();

monitor.start({
  metrics: ['lcp', 'fid', 'cls', 'longtask'],
  samplingInterval: 1000,
  onMetricsUpdate: (metrics) => {
    updateDashboard(metrics);
  },
  onLongTask: (task) => {
    console.warn(`长任务: ${task.duration}ms, 开始于: ${task.startTime}`);
  }
});

// 导出报告
document.getElementById('export').onclick = async () => {
  const report = monitor.generateReport();
  const handle = await window.showSaveFilePicker({
    suggestedName: `performance-report-${Date.now()}.json`
  });
  const writable = await handle.createWritable();
  await writable.write(JSON.stringify(report, null, 2));
  await writable.close();
};

📚 更多强大API速查

API用途浏览器支持
Screen Wake Lock防止屏幕休眠Chrome 84+
Contact Picker选择联系人Chrome 80+
Shape Detection API人脸/条码/文本识别Chrome 83+
Idle Detection检测用户空闲状态Chrome 94+
Periodic Background Sync后台定期同步Chrome 80+
WebCodecs音视频编解码Chrome 86+
Content Indexing API离线内容索引Chrome 84+

明日预告:设计系统实战 - 从0到1构建企业的组件库(设计令牌、无头组件、可访问性)

💡 浏览器智慧:每半年重新审视一次浏览器API,你总会有新的发现!