archives

« Bugzilla Issues Index

#3014 — Generator's iterator.next() queue'ing microtask while generator running?


Pretty strongly guessing this is going to be impossible or rejected, but I figured I'd just ask, since on the surface (in my ignorance) it seems like a fairly minor spec tweak.

Consider code like this:


var cache = {};
var getData(url) {
if (cache[url]) {
it.next( cache[url] );
}
else {
makeAjaxRequest( url, function(data) {
cache[url] = data;
it.next( data );
} );
}
}

function* main() {
var res1 = yield getData("http://some.url.1");
var res2 = yield getData("http://some.url.2");
console.log(res1 + res2);
}

var it = main();
it.next();



This code seems simple enough: request data, if in the in-memory cache, use it, otherwise fetch from server.

There's a kind of hidden/subtle bug, which is that it breaks in the case of fulfilling from the cache. The reason? Because you're calling `it.next( cache[url] )` in the middle of the `yield getData(..)` expression, so the generator is still running. An error is thrown.

The solution?


if (cache[url]) {
setTimeout( function(){
it.next( cache[url] );
}, 0 );
}


That's unfortunate, but it's yet another place where having no exposed hook to queue a micro-task forces reliance on ugly (and performance-troublesome) `setTimeout(..0)`.

--------

So, my question, in two parts...

1. is it at all possible that calling `next(..)` or `throw(..)` on a generator's iterator could queue a microtask for that rather than doing it directly?

For #1, it could be that it does this always, or it could be that it only enqueues a task if the generator is currently running.

Either way, at the end of the current execution thread, if the generator is no longer running, you could immediately drain those tasks (if any), rather than actually waiting for the next cycle.

The net result would be that generators would continue to work normally the way they already do, but in the special case where you call a `next(..)` or `throw(..)` on a running generator, THAT call would be queued to defer until the end of the thread, so that it didn't need to be an error.


After further consideration, this idea would never work, because you wouldn't be able to get back the return values from the `next()` call, which is obviously a deal breaker.

Please close. Apologies for the noise.