JavaScript: Generators
Values that change over time, such as interactive inputs and animation parameters, can represented as async generators. When a top-level generator is declared, code in other blocks sees the generator’s latest yielded value and runs whenever the generator yields a new value.
For example, here is a generator that increments once a second:
const j = (async function* () {
for (let j = 0; true; ++j) {
yield j;
await new Promise((resolve) => setTimeout(resolve, 1000));
}
})();
The value of j is: .
The value of j is: ${j}.
If the generator is synchronous, the generator will yield every animation frame, which is typically 60 frames per second:
const i = (function* () {
for (let i = 0; true; ++i) {
yield i;
}
})();
The value of i is: .
The value of i is: ${i}.
As another example, you can use the built-in Generators.observe
to represent the current pointer coordinates:
const pointer = Generators.observe((change) => {
const pointermoved = (event) => change([event.clientX, event.clientY]);
addEventListener("pointermove", pointermoved);
change([0, 0]);
return () => removeEventListener("pointermove", pointermoved);
});
Pointer is: .
Pointer is: ${pointer.map(Math.round).join(", ")}.
Here is a WebSocket that listens for Blockchain transactions:
const socket = new WebSocket("wss://ws.blockchain.info/inv");
invalidation.then(() => socket.close());
socket.addEventListener("open", () => socket.send(JSON.stringify({op: "unconfirmed_sub"})));
const message = Generators.observe((change) => {
const messaged = (event) => change(JSON.parse(event.data));
socket.addEventListener("message", messaged);
return () => socket.removeEventListener("message", messaged);
});
message.x // the most recently reported transaction
And here’s an HTML input element using Generators.input
:
const nameInput = display(document.createElement("input"));
const name = Generators.input(nameInput);
name