Installation
Repeater.js is available on npm in the CommonJS and ESModule formats.
$ npm install @repeaterjs/repeater
$ yarn add @repeaterjs/repeater
Requirements
The core @repeaterjs/repeater
module has no dependencies, but requires the following globals in order to work:
Promise
WeakMap
Symbol
Symbol.iterator
Symbol.asyncIterator
In addition, repeaters are most useful when used via async/await
and for await…of
syntax. You can transpile your code with babel or typescript to support enviroments which lack these features.
Examples
Logging timestamps with setInterval
import { Repeater } from "@repeaterjs/repeater";const timestamps = new Repeater(async (push, stop) => {push(Date.now());const interval = setInterval(() => push(Date.now()), 1000);await stop;clearInterval(interval);});(async function() {let i = 0;for await (const timestamp of timestamps) {console.log(timestamp);i++;if (i >= 10) {console.log("ALL DONE!");break; // triggers clearInterval above}}})();
Creating a repeater from a websocket
import { Repeater } from "@repeaterjs/repeater";const socket = new WebSocket("ws://echo.websocket.org");const messages = new Repeater(async (push, stop) => {socket.onmessage = (ev) => push(ev.data);socket.onerror = () => stop(new Error("WebSocket error"));socket.onclose = () => stop();await stop;socket.close();});(async function() {for await (const message of messages) {console.log(message);if (message === "close") {console.log("Closing!");break; // closes the socket}}})();socket.onopen = () => {socket.send("hello"); // "hello"socket.send("world"); // "world"socket.send("close"); // "close", "Closing!"};
Konami Code and canceling if Escape is pressed
Listening for theimport { Repeater } from "@repeaterjs/repeater";const keys = new Repeater(async (push, stop) => {const listener = (ev) => {if (ev.key === "Escape") {stop();} else {push(ev.key);}};window.addEventListener("keyup", listener);await stop;window.removeEventListener("keyup", listener);});const konami = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];(async function() {let i = 0;for await (const key of keys) {if (key === konami[i]) {i++;} else {i = 0;}if (i >= konami.length) {console.log("KONAMI!!!");break; // removes the keyup listener}}})();
Converting an observable to an async iterator
import { Subject } from "rxjs";import { Repeater } from "@repeaterjs/repeater";const observable = new Subject();const repeater = new Repeater(async (push, stop) => {const subscription = observable.subscribe({next: (value) => push(value),error: (err) => stop(err),complete: () => stop(),});await stop;subscription.unsubscribe();});(async function() {try {for await (const value of repeater) {console.log("Value: ", value);}} catch (err) {console.log("Error caught: ", err);}})();observable.next(1);// Value: 1observable.next(2);// Value: 2observable.error(new Error("Hello from observable"));// Error caught: Error: Hello from observable