-
-
Save elclanrs/45800747e7c2c126594fa1257688bf85 to your computer and use it in GitHub Desktop.
3 examples of using Async Generators and Async Iteration in JavaScript!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
// ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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" | |
// ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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