ReadableStream 可配合 setInterval 或 requestAnimationFrame 实现计时器数据流,通过 controller.push 推送时间戳等数据,并在 controller.signal.onabort 中清理定时器;需检查 controller.desiredSize > 0 避免向已关闭流推送。

ReadableStream 构造函数本身不直接用于创建“计时器数据流”,但它可以配合 setInterval 或 requestAnimationFrame,把时间戳、毫秒差或自定义 tick 事件封装成可消费的流——这是前端实现响应式定时推送的现代方式。
核心思路:用控制器 push 时间数据
ReadableStream 接收一个执行器函数,其中通过 controller.push() 主动推送数据。计时器逻辑(如每 100ms 推一次当前时间)就放在这个函数里,同时需处理流关闭时的清理(清除定时器)。
- 构造时传入执行器函数,接收
controller参数 - 在执行器内调用
setInterval,每次触发时controller.push({ time: Date.now(), delta: ... }) - 监听
controller.signal.onabort,在流被取消(如reader.cancel()或 GC)时clearInterval - 注意:不能在流已关闭后继续 push,可用
controller.desiredSize > 0或标志位判断是否活跃
基础实现:每秒推送一次时间戳
以下是一个最小可用示例,创建每秒推送当前 Date.now() 的流:
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
const timerStream = new ReadableStream({
start(controller) {
let lastTime = Date.now();
const interval = setInterval(() => {
const now = Date.now();
const delta = now - lastTime;
lastTime = now;
<pre class="brush:php;toolbar:false;"> // 避免向已关闭的流推送
if (controller.desiredSize > 0) {
controller.push({
time: now,
delta,
timestamp: new Date(now).toISOString()
});
}
}, 1000);
// 清理定时器
controller.signal.addEventListener('abort', () => {
clearInterval(interval);
});} });
// 消费示例 const reader = timerStream.getReader(); async function read() { while (true) { const { done, value } = await reader.read(); if (done) break; console.log(value); // { time: 1718234567890, delta: 1000, timestamp: "2024-06-13T10:22:47.890Z" } } } read();
增强控制:支持启停、精度调节与终止条件
实际项目中常需暂停、调整间隔、或达到某次数后自动结束。可封装为工厂函数,接受配置参数:
- intervalMs:推送间隔(默认 1000)
-
maxTicks:最大推送次数(
undefined表示无限) -
getTickData:自定义返回数据结构的函数(例如返回
{ elapsed: number }) - 内部维护
tickCount和isActive标志,配合controller.close()终止流
注意事项与边界处理
ReadableStream 计时器不是替代 setTimeout 的通用工具,它适用于需要流式消费、与 TransformStream 管道组合、或对接 Response.body 模拟等场景:
- 高频率推送(如 10ms)可能导致背压问题,应检查
controller.desiredSize再 push - 页面后台运行时,
setInterval可能被节流,如需精准,改用performance.now()+requestAnimationFrame(但注意 RAF 在后台暂停) - 避免在 push 中执行耗时操作,否则影响流调度;复杂计算建议放在 transform 阶段
- 流一旦 close 或 error,不可恢复,需重新构造新实例
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










