-
-
Save getify/0e1b1ef7e270c6d16f4d1d616296eda4 to your computer and use it in GitHub Desktop.
a better "async generator", where `return(..)` immediately tears it down? Insipired from: https://alinacierdem.com/the-problem-with-async-generators/
This file contains 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
// NOTE: ag(..) is defined in 2.js below | |
for await (let v of ag("hello")) { | |
console.log(`v: ${v}`); | |
} | |
// a: hello | |
// b | |
// v: 42 | |
// c: some data: 10 | |
// d | |
// v: some data: 50 | |
// .... waiting 5 seconds .... | |
// e | |
// finally! | |
// ******************************************************** | |
for await (let v of ag("hello")) { | |
console.log(`v: ${v}`); | |
if (v == "some data: 50") { | |
break; | |
} | |
} | |
// a: hello | |
// b | |
// v: 42 | |
// c: some data: 10 | |
// d | |
// v: some data: 50 | |
// finally! | |
// ******************************************************** | |
var it = ag("hello"); | |
for await (let v of it) { | |
console.log(`v: ${v}`); | |
if (v == "some data: 50") { | |
setTimeout(function(){ it.return(); },10); | |
} | |
} | |
// a: hello | |
// b | |
// v: 42 | |
// c: some data: 10 | |
// d | |
// v: some data: 50 | |
// .... waiting only 10 milliseconds .... | |
// finally! |
This file contains 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
// NOTE: asyncGenerator(..) utility is defined in 3.js below | |
var ag = asyncGenerator(function *main(pwait,a){ | |
// NOTE: `pwait` parameter here is how we fake an `await` inside a normal generator | |
// for it to work, you have to do `yield pwait(..)`, not just `pwait(..)` | |
try { | |
console.log(`a: ${a}`); | |
yield pwait(delay(500)); // <---- fake `await` | |
console.log("b"); | |
yield 42; | |
var c = yield pwait(getData(10)); // <---- fake `await` | |
console.log(`c: ${c}`); | |
yield pwait(delay(500)); // <---- fake `await` | |
console.log("d"); | |
yield getData(50); // but THIS one is just yielding a promise out through the async generator machinery, which is where the "v: some data: 50" log message comes from | |
yield pwait(delay(5000)); // <---- fake `await` | |
console.log("e"); | |
yield pwait(delay(500)); // <---- fake `await` | |
return 250; | |
} | |
finally { | |
console.log("finally!"); | |
} | |
}); |
This file contains 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
// inspired by: https://alinacierdem.com/the-problem-with-async-generators/ | |
function asyncGenerator(gen) { | |
var awaiteds = new WeakSet(); | |
var unset = Symbol("unset"); | |
var returned = Symbol("returned"); | |
return function wrapped(...args){ | |
var def = deferred(); | |
var it = gen(pwait,...args); | |
var ait = runner(it,def.pr); | |
var aitRet = ait.return; | |
ait.return = doReturn; | |
return ait; | |
// *************************** | |
function doReturn(v){ | |
try { | |
def.pr.resolved = true; | |
def.resolve(returned); | |
return it.return(v); | |
} | |
finally { | |
aitRet.call(ait); | |
ait.return = aitRet; | |
def = ait = aitRet = null; | |
} | |
} | |
}; | |
// *************************** | |
function pwait(v) { | |
var pr = Promise.resolve(v); | |
awaiteds.add(pr); | |
return pr; | |
} | |
async function *runner(it,complete) { | |
var res; | |
var excp = unset; | |
try { | |
while (!complete.resolved) { | |
if (excp !== unset) { | |
res = it.throw(excp); | |
} | |
else { | |
res = it.next(res); | |
} | |
if (isPromise(res.value)) { | |
if (awaiteds.has(res.value)) { | |
awaiteds.delete(res.value); | |
try { | |
res = await Promise.race([ | |
complete, | |
res.value, | |
]); | |
if (res === returned) { | |
return; | |
} | |
} | |
catch (err) { | |
excp = err; | |
} | |
} | |
else { | |
res = yield res.value; | |
} | |
} | |
else if (res.done) { | |
return res.value; | |
} | |
else { | |
res = yield res.value; | |
} | |
} | |
} | |
finally { | |
it = complete = null; | |
} | |
} | |
function isPromise(pr) { | |
return (pr && typeof pr == "object" && typeof pr.then == "function"); | |
} | |
function deferred() { | |
var resolve; | |
var pr = new Promise(function c(res){ | |
resolve = res; | |
}); | |
return { pr, resolve }; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment