# Web Monitor SDK

一个轻量级的前端监控 SDK，用于收集网页性能指标、错误信息和用户行为数据。

## 特性

- 🚀 轻量级，零依赖
- 📊 性能监控
  - 首屏加载时间
  - FCP (First Contentful Paint)
  - LCP (Largest Contentful Paint) 
  - FID (First Input Delay)
  - CLS (Cumulative Layout Shift)
- 🐛 错误监控
  - JS 运行时错误
  - Promise 未捕获异常
  - 资源加载错误
  - HTTP 请求异常
- 👨‍💻 用户行为跟踪
  - PV/UV 统计
  - 用户点击行为
  - 页面停留时间
  - 路由变化

## 安装

```bash
npm install web-monitor-sdk
```

## 核心功能

### 1. 性能监控

- **页面加载性能**
  - 首屏加载时间(FP)
  - 首次内容绘制(FCP)
  - 最大内容绘制(LCP)
  - 首次输入延迟(FID)
  - 累积布局偏移(CLS)
  
- **资源加载性能**
  - 资源加载时间统计
  - 资源加载瀑布图
  - 静态资源缓存命中率

- **接口性能**
  - API 请求耗时统计
  - 接口成功/失败率
  - 慢请求追踪

### 2. 错误监控

- **JS 错误**
  - 运行时错误捕获
  - Promise 异常监控
  - 跨域脚本错误处理
  
- **资源错误**
  - 图片/脚本加载失败
  - HTTP 404/500 等状态码监控
  - 接口超时监控

- **控制台错误**
  - console.error 监控
  - 自定义错误上报

### 3. 用户行为分析

- **页面访问**
  - PV/UV 统计
  - 访问来源分析
  - 停留时长统计
  
- **用户交互**
  - 点击行为追踪
  - 滚动深度分析
  - 表单操作记录

## 优化措施

### 1. 数据上报优化

- **批量上报**
  - 采用队列缓存，批量上报减少请求次数
  - 支持配置上报阈值和时间间隔
  - 页面卸载前确保数据发送完成

- **数据压缩**
  - 采用 JSON 压缩算法
  - 大数据量采用分片上传
  - 支持 gzip 压缩

### 2. 性能优化

- **采样控制**
  - 支持按比例采样上报
  - 重要用户/错误数据优先上报
  - 动态调整采样率

- **节流与防抖**
  - 高频事件节流处理
  - 连续错误防抖优化
  - 避免重复上报

### 3. 稳定性优化

- **容错处理**
  - SDK 异常自动恢复
  - 关键流程容错
  - 上报失败重试机制

- **浏览器兼容**
  - 优雅降级处理
  - Polyfill 按需加载
  - 主流浏览器全覆盖

## 实现细节

### 1. 性能数据采集
- 使用 Performance API 采集加载性能
- 使用 PerformanceObserver 监听性能事件
- 通过 requestAnimationFrame 计算渲染性能

### 2. 错误监控实现
- window.onerror 捕获 JS 运行时错误
- unhandledrejection 事件捕获 Promise 异常
- 重写 XMLHttpRequest 和 fetch 监控接口异常

### 3. 行为数据收集
- 使用事件委托优化点击监听
- 通过 MutationObserver 监控 DOM 变化
- 路由监听支持 hash 和 history 模式

### 4. 上报优化实现
- 使用 requestIdleCallback 在空闲时段上报
- 采用 Navigator.sendBeacon 处理页面卸载场景
- IndexedDB 存储离线数据
// ... 前面内容保持不变 ...

## 优化措施及实现

### 1. 数据上报优化

#### 批量上报实现
```typescript
class Reporter {
  private queue: any[] = [];
  private timer: number | null = null;
  private readonly threshold = 10; // 队列阈值
  private readonly interval = 5000; // 上报间隔

  push(data: any) {
    this.queue.push(data);
    if (this.queue.length >= this.threshold) {
      this.flush();
    } else {
      this.setupTimer();
    }
  }

  private setupTimer() {
    if (!this.timer) {
      this.timer = window.setTimeout(() => this.flush(), this.interval);
    }
  }

  private flush() {
    if (this.queue.length === 0) return;
    
    // 使用 sendBeacon 保证页面卸载时数据发送
    const data = JSON.stringify(this.queue);
    navigator.sendBeacon('/collect', data);
    
    this.queue = [];
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  }
}
```

#### 数据压缩实现
```typescript
class DataCompressor {
  compress(data: any) {
    // 1. 移除冗余字段
    const cleaned = this.removeRedundant(data);
    
    // 2. 数据编码压缩
    const compressed = this.encode(cleaned);
    
    // 3. 大数据分片处理
    return this.slice(compressed);
  }

  private encode(data: any) {
    // 短字符串映射
    const dictionary: Record<string, string> = {
      'error': 'e',
      'warning': 'w',
      'info': 'i',
      'performance': 'p'
    };
    
    return JSON.stringify(data).replace(
      /("error"|"warning"|"info"|"performance")/g,
      match => dictionary[match.replace(/"/g, '')] || match
    );
  }
}
```

### 2. 性能优化实现

#### 采样控制实现
```typescript
class SamplingController {
  private readonly defaultRate = 0.1; // 默认采样率10%
  
  shouldReport(data: any): boolean {
    // 错误数据100%采样
    if (data.type === 'error') return true;
    
    // VIP用户100%采样
    if (data.userType === 'vip') return true;
    
    // 其他数据按比例采样
    return Math.random() < this.getRate(data.type);
  }

  private getRate(type: string): number {
    const rateMap = {
      performance: 0.1,
      behavior: 0.05,
      custom: 0.01
    };
    return rateMap[type] || this.defaultRate;
  }
}
```

#### 节流防抖实现
```typescript
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  wait: number
): (...args: Parameters<T>) => void {
  let timer: number | null = null;
  
  return function(...args: Parameters<T>) {
    if (timer) clearTimeout(timer);
    timer = window.setTimeout(() => {
      fn.apply(this, args);
      timer = null;
    }, wait);
  };
}

// 错误上报防抖
const reportError = debounce((error: Error) => {
  reporter.send({
    type: 'error',
    message: error.message,
    stack: error.stack
  });
}, 2000);
```

### 3. 稳定性优化实现

#### 容错处理实现
```typescript
class ErrorBoundary {
  private retryTimes = 3;
  
  async sendData(data: any) {
    for (let i = 0; i < this.retryTimes; i++) {
      try {
        await this.send(data);
        return;
      } catch (err) {
        if (i === this.retryTimes - 1) {
          // 存储到 IndexedDB 待后续上报
          await this.saveToIndexedDB(data);
        }
        // 指数退避重试
        await this.sleep(Math.pow(2, i) * 1000);
      }
    }
  }

  private async saveToIndexedDB(data: any) {
    const db = await this.openDB();
    const tx = db.transaction('reports', 'readwrite');
    await tx.objectStore('reports').add(data);
  }
}
```

#### 浏览器兼容实现
```typescript
class BrowserAdapter {
  // Performance API 兼容
  getFirstPaint() {
    if (window.performance && window.performance.getEntriesByType) {
      const [entry] = performance.getEntriesByType('paint');
      return entry ? entry.startTime : null;
    }
    // 降级方案
    return this.getFallbackTiming();
  }

  // 优雅降级
  private getFallbackTiming() {
    if (performance.timing) {
      return performance.timing.domLoading - performance.timing.navigationStart;
    }
    return Date.now(); // 最后的降级方案
  }
}
```

### 4. 离线存储实现
```typescript
class OfflineStorage {
  private readonly DB_NAME = 'monitor_sdk';
  private readonly STORE_NAME = 'offline_data';
  
  async init() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.DB_NAME, 1);
      
      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve(request.result);
      
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        db.createObjectStore(this.STORE_NAME, { 
          keyPath: 'id',
          autoIncrement: true 
        });
      };
    });
  }

  async saveOfflineData(data: any) {
    const db = await this.init();
    return new Promise((resolve, reject) => {
      const tx = (db as IDBDatabase)
        .transaction(this.STORE_NAME, 'readwrite');
      const store = tx.objectStore(this.STORE_NAME);
      
      const request = store.add({
        data,
        timestamp: Date.now()
      });
      
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }
}
```

## 使用示例

```typescript
const monitor = new WebMonitor({
  appId: 'your-app-id',
  // 开启性能监控
  enablePerformance: true,
  // 开启错误监控
  enableError: true,
  // 采样率配置
  sampling: {
    performance: 0.1,
    behavior: 0.05
  },
  // 上报配置
  report: {
    threshold: 10,
    interval: 5000
  }
});

// 启动监控
monitor.start();
```

这些优化措施的实现代码展示了：

1. 如何实现批量上报和数据压缩
2. 采样控制的具体逻辑
3. 防抖节流的实现方式
4. 错误重试和容错处理
5. 浏览器兼容性处理
6. 离线数据存储的实现

通过这些实现，可以确保监控 SDK 在各种场景下都能稳定高效地运行。