Skip to content

Instantly share code, notes, and snippets.

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 hoehrmann/5792533 to your computer and use it in GitHub Desktop.
Save hoehrmann/5792533 to your computer and use it in GitHub Desktop.
Abusing JavaScript generators and yield one can create task schedulers that essentially allow to write code that waits without blocking for asynchronous events. Originally http://lists.w3.org/Archives/Public/www-archive/2008Jul/0009.html and http://lists.w3.org/Archives/Public/www-archive/2013Apr/0043.html The difference between the two versions…
function OnYieldWaitForEvent(cor, target, name, phase) {
var self = arguments.callee;
target.addEventListener(name, function(evt) {
// We need to unregister the listener to save resources
// and to avoid getting called if the event occurs again
evt.currentTarget.removeEventListener(name, self, phase);
// Resume the waiting function
cor.next();
}, phase);
};
function ExecWithOnYield(func) {
var generator = new func;
generator.next();
// There is no arguments.generator or `this generator` yet
// and arguments.callee refers to the Function object, so
// we have to pass a self-reference to the instance.
generator.send(generator);
};
function test() {
var self = yield;
// Create a new <img> object
var img1 = new Image(315, 48);
OnYieldWaitForEvent(self, img1, 'load', false);
img1.src = 'http://www.w3.org/Icons/w3c_main';
yield; // wait for img1 'load'
// ... load more images here ...
// Now draw them all on a <canvas>
// Signal we are done so the event handler does not have to
// catch an exception that would otherwise be generated.
yield 'done';
};
ExecWithOnYield(test);
function OnYieldWaitForEvent(target, name, useCapture) {
return function(resume) {
var listener;
listener = function(){
target.removeEventListener(name, listener, useCapture);
resume();
};
target.addEventListener(name, listener, useCapture);
}
}
function ExecWithOnYield(func) {
var generator = new func;
var ExecOneStep;
ExecOneStep = function(){
try {
var wrapped = generator.next();
// TODO: what if `wrapped` throws `StopIteration`?
wrapped(ExecOneStep);
}
catch (e) {
if (e instanceof StopIteration) {
console.log("StopIteration");
} else {
console.log("other exception");
}
}
}
ExecOneStep(generator);
};
function test() {
var img1 = new Image(315, 48);
img1.src = 'http://www.w3.org/Icons/w3c_main';
yield OnYieldWaitForEvent(img1, 'load', false);
console.log("img1 has loaded when we get here");
};
ExecWithOnYield(test);
@hollowdoor
Copy link

With all the addEventListener, and removeEventListener would this cause issues for a ton of events? Like if you were to do mouse move tracking in a loop?

Using it for clicks would probably be ok.

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