a better "async generator", where `return(..)` immediately tears it down? Insipired from: https://alinacierdem.com/the-problem-with-async-generators/
// 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! |
// 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!"); | |
} | |
}); |
// 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