← 中文资源

简体中文版本

固定容量环形缓冲区

用固定容量环形缓冲区保存最近的项目,支持覆盖淘汰、按下标访问、迭代和清空。

阅读英文原文

功能说明

CircularBuffer<T> 在固定长度的数组中循环写入数据,写满后新元素覆盖最旧的元素,始终保持最近的 capacity 条记录。它适合保存最近日志、性能采样、命令历史、滑动统计窗口等场景,内存占用在构造时就确定,不会随运行时间增长。

缓冲区维护写指针 head 和当前元素数量 count。逻辑起点通过 head - count 计算,因此 at(0) 始终是最旧的有效元素,at(size - 1) 是最新元素。push 会返回被覆盖的旧值,未满时返回 undefined;toArray 和迭代器按从旧到新的顺序输出。

关键代码

写入时先判断是否已满,已满则记录将被覆盖的值,再推进写指针:

const evicted =
  this.count === this.capacity ? this.items[this.head] : undefined;
this.items[this.head] = value;
this.head = (this.head + 1) % this.capacity;
if (this.count < this.capacity) this.count += 1;
return evicted;

at 先把逻辑下标转换为物理下标,并校验范围,避免读到未初始化槽位。

使用注意

push 返回 undefined 既可能表示“尚未满、没有淘汰”,也可能表示被淘汰的旧值本身就是 undefined;如果需要严格区分,应改用包装对象或先检查 full。容量必须为正整数,构造后不可调整。at 越界会抛 RangeError,而 push 和 toArray 不会。

clear 会清空所有槽位并重置指针,但不会改变容量。迭代器每次通过 at 读取,遍历过程中如果调用 push,结果可能包含新写入的数据,不建议在迭代时修改缓冲区。该结构不是线程安全的,也不提供按值删除。元素为对象时只保存引用,不会克隆。

验证方式

示例容量为 3,依次写入 1、2、3 时 push 返回 undefined;写入 4 时返回被覆盖的 1。此时 toArray 应为 [2, 3, 4],at(0) 为 2,at(2) 为 4,full 为 true,展开迭代器也得到相同数组。调用 clear 后大小为 0,再访问 at(0) 应抛出 index out of range: 0。