npm package: @knotx/plugins-batch
Description: Batch Plugin for Knotx
Author: boenfu
Latest version: 0.5.10

# @knotx/plugins-batch

批处理插件，为 KnotX 提供操作批处理功能。

## 安装

```bash
npm install @knotx/plugins-batch
```

## 概述

Batch 插件为 KnotX 提供了操作批处理功能，能够将多个连续的节点操作合并为一个批处理操作，从而提高性能并减少历史记录条目。该插件通过 RxJS 的缓冲机制实现操作合并。

## 实现原理

Batch 插件的核心实现原理：

1. **操作拦截**：拦截节点操作管道，识别可批处理的操作
2. **缓冲机制**：使用 RxJS 的 `buffer` 和 `timer` 实现时间窗口内的操作合并
3. **操作合并**：将多个单独操作合并为一个批处理操作
4. **递归处理**：支持嵌套批处理操作的扁平化处理

## 依赖关系

### 核心依赖
- `@knotx/core`：提供基础插件架构和数据管理
- `@knotx/decorators`：提供装饰器支持
- `rxjs`：提供响应式编程支持

### 自动依赖
- `@knotx/core` 中的节点操作管道：自动集成到操作处理流程中

## API 文档

### 主要类

#### Batch

批处理插件的主要类，继承自 `BasePlugin`。

```typescript
export class Batch extends BasePlugin<'batch'> {
  name = 'batch' as const
}
```

### 实现逻辑

该插件自动工作，无需手动配置。它会：

1. **监听节点操作**：自动拦截所有节点操作
2. **判断批处理条件**：如果操作包含 `draftId`，则立即处理（不批处理）
3. **批量处理**：将 100ms 内的操作合并为一个批处理操作
4. **递归扁平化**：处理嵌套的批处理操作

## 使用示例

### 基本用法

```typescript
import { Batch } from '@knotx/plugins-batch'

const engine = new Engine({
  plugins: [Batch],
})

// 批处理会自动工作，无需额外配置
```

### 与其他插件集成

```typescript
import { Batch } from '@knotx/plugins-batch'
import { Drag } from '@knotx/plugins-drag'
import { History } from '@knotx/plugins-history'

const engine = new Engine({
  plugins: [Batch, History, Drag],
})

// 批处理会优化历史记录和拖拽操作
```

### 观察批处理效果

```typescript
class BatchObserverPlugin extends BasePlugin {
  @inject.nodesManager()
  nodesManager!: DataManager<Node>

  @OnInit
  init() {
    // 监听节点操作
    this.nodesManager.operations$.subscribe((operation) => {
      if (operation.type === 'batch') {
        console.log('批处理操作:', operation.operations.length, '个操作')
      }
      else {
        console.log('单个操作:', operation.type)
      }
    })
  }
}
```

## 工作原理详解

### 操作类型判断

```typescript
// 源码示例（简化版）
transform: operations$ => pipe(
  exhaustMap((firstOperation) => {
    // 如果是草稿操作，立即处理
    if ('draftId' in firstOperation) {
      return of([firstOperation])
    }

    // 否则等待缓冲窗口
    return operations$.pipe(
      startWith(firstOperation),
      buffer(timer(100)), // 100ms 缓冲窗口
      take(1),
    )
  }),
  map(operations => ({
    type: 'batch' as const,
    operations: operations.flatMap(op =>
      op.type === 'batch' ? op.operations : op
    ),
  })),
)
```

### 批处理优势

1. **性能提升**：减少频繁的重渲染和状态更新
2. **历史记录优化**：将多个操作合并为一个历史记录条目
3. **用户体验**：提供更流畅的操作感受
4. **资源节约**：减少不必要的计算和内存分配

## 实际应用场景

### 拖拽操作优化

```typescript
// 拖拽过程中会产生大量位置更新操作
// 批处理会将这些操作合并为一个批处理操作

engine.dispatchNodeOperation({
  type: 'update',
  data: { id: 'node1', position: { x: 100, y: 100 } },
})

engine.dispatchNodeOperation({
  type: 'update',
  data: { id: 'node1', position: { x: 101, y: 101 } },
})

engine.dispatchNodeOperation({
  type: 'update',
  data: { id: 'node1', position: { x: 102, y: 102 } },
})

// 以上操作会被合并为一个批处理操作
```

### 批量添加节点

```typescript
// 批量添加多个节点
for (let i = 0; i < 10; i++) {
  engine.dispatchNodeOperation({
    type: 'add',
    data: { id: `node${i}`, position: { x: i * 100, y: 100 } },
  })
}

// 这些操作会被合并为一个批处理操作
```

### 复杂操作序列

```typescript
// 复杂的操作序列
engine.dispatchNodeOperation({
  type: 'add',
  data: { id: 'node1', position: { x: 100, y: 100 } },
})

engine.dispatchNodeOperation({
  type: 'update',
  data: { id: 'node1', data: { label: 'Updated' } },
})

engine.dispatchNodeOperation({
  type: 'add',
  data: { id: 'node2', position: { x: 200, y: 200 } },
})

// 这些操作会被合并为一个批处理操作
```

## 性能影响

### 优化效果

1. **减少重渲染**：批处理后的操作只触发一次重渲染
2. **优化历史记录**：减少历史记录条目数量
3. **提升响应性**：减少操作处理的延迟

### 缓冲时间调整

批处理使用固定的 100ms 缓冲窗口，这个时间在性能和响应性之间取得平衡：

- **太短**：可能无法有效合并操作
- **太长**：可能影响用户体验的实时性

## 与其他插件的交互

### History 插件

```typescript
// 批处理会大大减少历史记录条目
const engine = new Engine({
  plugins: [Batch, History],
})

// 原本 100 个操作可能只产生 1 个历史记录条目
```

### Drag 插件

```typescript
// 拖拽操作会产生大量位置更新
// 批处理会将这些更新合并
const engine = new Engine({
  plugins: [Batch, Drag],
})
```

## 文件目录结构

```
packages/plugins-batch/
├── src/
│   ├── batch.ts                # 主要实现文件
│   └── index.ts               # 导出文件
├── dist/                      # 构建输出目录
├── package.json              # 包配置文件
├── build.config.ts           # 构建配置
├── tsconfig.json             # TypeScript 配置
├── eslint.config.mjs         # ESLint 配置
└── CHANGELOG.md              # 更新日志
```

### 核心文件说明

- **batch.ts**：包含 Batch 插件的主要实现，包括操作拦截、缓冲机制和批处理逻辑
- **index.ts**：导出 Batch 类和相关类型定义

## 最佳实践

### 性能优化

1. **合理使用**：批处理对于频繁的操作序列最有效
2. **配合其他插件**：与 History 和 Drag 插件配合使用效果最佳
3. **监控效果**：在开发阶段监控批处理的效果

### 调试建议

1. **操作日志**：记录批处理前后的操作数量
2. **性能测试**：对比启用/禁用批处理的性能差异
3. **内存监控**：确保批处理不会导致内存泄漏

## 注意事项

1. **草稿操作**：包含 `draftId` 的操作不会被批处理
2. **操作顺序**：批处理保持操作的原始顺序
3. **错误处理**：批处理操作中的错误会影响整个批次
4. **时间窗口**：100ms 的缓冲时间是固定的，不可配置

## 许可证

MIT