Skip to content

Instantly share code, notes, and snippets.

@peter-leonov
Last active April 13, 2020 08:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peter-leonov/f0c61dae5c8409030b8c3a192ddb63c4 to your computer and use it in GitHub Desktop.
Save peter-leonov/f0c61dae5c8409030b8c3a192ddb63c4 to your computer and use it in GitHub Desktop.
Array<Promise<T>> -> AsyncIterator<T>
async function main() {
async function f1() {
return new Promise((res) => {
setTimeout(() => {
res("1.1");
}, 1000);
});
}
async function f2() {
return new Promise((res) => {
setTimeout(() => {
res("2.1");
}, 100);
});
}
function streamManual(pArr) {
return {
[Symbol.asyncIterator]() {
// having this instead of a good promise queue with pushback
let promises = [];
let resolves = [];
let j = 0;
function done(value) {
resolves[j++]({
done: false,
value,
});
}
pArr.forEach((p) => {
p.then(done);
promises.push(
new Promise((res) => {
resolves.push(res);
})
);
});
let i = 0;
return {
next() {
if (i < pArr.length) {
return promises[i++];
} else {
return Promise.resolve({
done: true,
value: undefined,
});
}
},
};
},
};
}
async function* streamNative(pArr) {
let resolve;
function done(v) {
resolve(v);
}
pArr.forEach((p) => p.then(done));
for (let i = 0; i < pArr.length; i++) {
// It is safe to assume .next() will not be called while we are waiting,
// as the async gemerator has an internal queue for us:
// https://2ality.com/2016/10/asynchronous-iteration.html#queuing-next()-invocations
// https://www.typescriptlang.org/play?#code/IYZwngdgxgBAZgV2gFwJYHsICoYmQJwFNgBbARhgAoBKAbwCgYZ6BfIA
yield new Promise((res) => {
resolve = res;
});
}
}
async function* runParallel(pArr) {
const res = new Array(pArr.length).fill(undefined);
for await (const [v, i] of streamManual(
pArr.map((p, i) => p.then((v) => [v, i]))
)) {
res[i] = v;
yield res;
}
}
// runParallel([f1(), f2()]);
for await (const results of runParallel([f1(), f2()])) {
console.log(results);
}
/**
* should output 2 lines:
*
* [undefined, "2.1"] // (after 100 ms)
* ["1.1", "2.1"] // (after 1000 ms)
*/
}
main()
.then(() => {
console.log("done");
})
.catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment