Skip to content

Instantly share code, notes, and snippets.

@noseratio
Last active March 28, 2021 22:09
Show Gist options
  • Save noseratio/721fea7443b74a929ea93c8f6a18cec4 to your computer and use it in GitHub Desktop.
Save noseratio/721fea7443b74a929ea93c8f6a18cec4 to your computer and use it in GitHub Desktop.
Async generators and "for await" in JavaScript
// by @noseratio
// https://twitter.com/noseratio/status/1297517388552757249?s=20
// gist: https://gist.github.com/noseratio/721fea7443b74a929ea93c8f6a18cec4/edit
// RunKit: https://runkit.com/noseratio/async-generators-and-for-await-in-javascript
async function delay(ms) {
await new Promise(r => setTimeout(r, ms));
return ms;
}
// an array of promises to iterate through with "for await"
function array() {
return [delay(100), delay(200), delay(300)];
}
// a synchronous generator of promises to iterate through with "for await"
function* generator() {
yield delay(100);
yield delay(200);
yield delay(300);
}
// an asynchronous generator of promises to iterate through with "for await"
async function* asyncGenerator() {
yield await delay(100);
yield await delay(200);
yield await delay(300);
}
// Simulate a "for await" loop in JavaScript,
// note that "await 1" is still a valid statement,
// which is essentially the same as "await Promise.resolve(1)"
async function forEachAsync(iterable, bodyFunc) {
const iterator = (
iterable[Symbol.asyncIterator] ||
iterable[Symbol.iterator]).call(iterable);
while (true) {
const { value, done } = await iterator.next();
const awaitedValue = await value;
if (done) {
return awaitedValue;
}
await bodyFunc(awaitedValue);
}
}
// test with "for await"
async function testForAwait(iterable) {
let start = Date.now();
for await (let value of iterable) {
console.log(`value: ${value}, lapse: ${Date.now() - start}`)
}
}
// test with "forEachAsync"
async function testForEach(iterable) {
let start = Date.now();
await forEachAsync(iterable, value => {
console.log(`value: ${value}, lapse: ${Date.now() - start}`)
})
}
// test all three sources
async function test(method) {
await delay(100); // kick the runkit runtime
console.log("- array")
await method(array());
console.log("- generator")
await method(generator());
console.log("- async generator")
await method(asyncGenerator());
}
async function main() {
console.log("testForAwait")
await test(testForAwait);
console.log("testForEach")
await test(testForEach);
}
main().then(() => console.log("Finished"), e => console.log(e));
@noseratio
Copy link
Author

Inspired by this tweet of @bengl.

@hvent90
Copy link

hvent90 commented Aug 23, 2020

Thanks for sharing. How does the loop on lines L38-L45 exit, given while (true)?

@j-blandford
Copy link

j-blandford commented Aug 23, 2020

@hvent90 the return statement L42 exits the function after going through every await message available

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment