Skip to content

Instantly share code, notes, and snippets.

@elclanrs
Forked from nybblr/1-easy.js
Created December 25, 2017 23:32
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save elclanrs/45800747e7c2c126594fa1257688bf85 to your computer and use it in GitHub Desktop.
Save elclanrs/45800747e7c2c126594fa1257688bf85 to your computer and use it in GitHub Desktop.
3 examples of using Async Generators and Async Iteration in JavaScript!
// Create a Promise that resolves after ms time
var timer = function(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
};
// Repeatedly generate a number starting
// from 0 after a random amount of time
var source = async function*() {
var i = 0;
while (true) {
await timer(Math.random() * 1000);
yield i++;
}
};
// Return a new async iterator that applies a
// transform to the values from another async generator
var map = async function*(stream, transform) {
for await (let n of stream) {
yield transform(n);
}
};
// Tie everything together
var run = async function() {
var stream = source();
// Square values generated by source() as they arrive
stream = map(stream, n => n * n);
for await (let n of stream) {
console.log(n);
}
};
run();
// => 0
// => 1
// => 4
// => 9
// ...
// Generate a Promise that listens only once for an event
var oncePromise = (emitter, event) => {
return new Promise(resolve => {
var handler = (...args) => {
emitter.removeEventListener(event, handler);
resolve(...args);
};
emitter.addEventListener(event, handler);
});
};
// Add an async iterator to all WebSockets
WebSocket.prototype[Symbol.asyncIterator] = async function*() {
while(this.readyState !== 3) {
yield (await oncePromise(this, 'message')).data;
}
};
// Tie everything together
var run = async () => {
var ws = new WebSocket('ws://localhost:3000/');
for await (let message of ws) {
console.log(message);
}
};
run();
// => "hello"
// => "sandwich"
// => "otters"
// ...
// Tie everything together
var run = async () => {
var i = 0;
var clicks = streamify('click', document.querySelector('body'));
clicks = filter(clicks, e => e.target.matches('a'));
clicks = distinct(clicks, e => e.target);
clicks = map(clicks, e => [i++, e]);
clicks = throttle(clicks, 500);
subscribe(clicks, ([ id, click ]) => {
console.log(id);
console.log(click);
click.preventDefault();
});
};
// Turn any event emitter into a stream
var streamify = async function*(event, element) {
while (true) {
yield await oncePromise(element, event);
}
};
// Generate a Promise that listens only once for an event
var oncePromise = (emitter, event) => {
return new Promise(resolve => {
var handler = (...args) => {
emitter.removeEventListener(event, handler);
resolve(...args);
};
emitter.addEventListener(event, handler);
});
};
// Only pass along events that meet a condition
var filter = async function*(stream, test) {
for await (var event of stream) {
if (test(event)) {
yield event;
}
}
};
// Transform every event of the stream
var map = async function*(stream, transform) {
for await (var event of stream) {
yield transform(event);
}
};
// Only pass along event if some time has passed since the last one
var throttle = async function*(stream, delay) {
var lastTime;
var thisTime;
for await (var event of stream) {
thisTime = (new Date()).getTime();
if (!lastTime || thisTime - lastTime > delay) {
lastTime = thisTime;
yield event;
}
}
};
var identity = e => e;
// Only pass along events that differ from the last one
var distinct = async function*(stream, extract = identity) {
var lastVal;
var thisVal;
for await (var event of stream) {
thisVal = extract(event);
if (thisVal !== lastVal) {
lastVal = thisVal;
yield event;
}
}
};
// Invoke a callback every time an event arrives
var subscribe = async (stream, callback) => {
for await (var event of stream) {
callback(event);
}
};
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment