Skip to content

Commit 645caac

Browse files
committed
✨ add interval() helper to consume a stream of intervals
[`setInterval()`][1] is a core JavaScript API that allows you to setup global state. As such, there really isn't any reason that you shouldn't consume it using structured concurrency. This adds an `interval()` function that constructs a stream that emits an item every time that the interval is triggered. ```ts let startTime = Date.now(); for (let _ of yield* each(interval(10))) { let elapsed = Date.now() - startTime; console.log(`elapsed time: ${elapsed} ms`); } ``` [1]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval
1 parent e729267 commit 645caac

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

lib/interval.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { resource } from "./instructions.ts";
2+
import { createSignal } from "./signal.ts";
3+
import type { Stream } from "./types.ts";
4+
5+
/**
6+
* Consume an interval as an infinite stream.
7+
*
8+
* ```ts
9+
* let startTime = Date.now();
10+
*
11+
* for (let _ of yield* each(interval(10))) {
12+
* let elapsed = Date.now() - startTime;
13+
* console.log(`elapsed time: ${elapsed} ms`);
14+
* yield* each.next();
15+
* }
16+
* ```
17+
* @param milliseconds - how long to delay between each item in the stream
18+
*/
19+
export function interval(milliseconds: number): Stream<void, never> {
20+
return resource(function* (provide) {
21+
let signal = createSignal<void, never>();
22+
23+
let id = setInterval(signal.send, milliseconds);
24+
25+
try {
26+
yield* provide(yield* signal);
27+
} finally {
28+
clearInterval(id);
29+
}
30+
});
31+
}

lib/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from "./instructions.ts";
55
export * from "./call.ts";
66
export * from "./run.ts";
77
export * from "./sleep.ts";
8+
export * from "./interval.ts";
89
export * from "./async.ts";
910
export * from "./abort-signal.ts";
1011
export * from "./result.ts";

test/interval.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { call, each, interval, race, run, sleep, spawn } from "../mod.ts";
2+
import { describe, expect, it } from "./suite.ts";
3+
4+
describe("interval", () => {
5+
it("can be iterated", async () => {
6+
await run(function* () {
7+
let task = yield* spawn(function* () {
8+
let total = 0;
9+
for (let _ of yield* each(interval(1))) {
10+
total++;
11+
if (total == 10) {
12+
return total;
13+
}
14+
yield* each.next();
15+
}
16+
});
17+
let result = yield* race([
18+
task,
19+
call(function* () {
20+
yield* sleep(50);
21+
return "interval not producing!";
22+
}),
23+
]);
24+
expect(result).toEqual(10);
25+
});
26+
});
27+
});

0 commit comments

Comments
 (0)