Skip to content

Instantly share code, notes, and snippets.

@creationix
Created June 21, 2011 05:56
Show Gist options
  • Save creationix/1037316 to your computer and use it in GitHub Desktop.
Save creationix/1037316 to your computer and use it in GitHub Desktop.
Userspace EventLoop for JavaScript
// Make a user-space event loop for doing smart event propigation with zero*
// race conditions.
//
// *(If you are unable to get at the event-source, an automatic setTimeout will
// be created, and there is a small chance some other native event may get in
// before it.)
function makeLoop() {
// Private //
// These two arrays are reused to kee the gc happy
var later = []; // A list of pending events for the next run of the loop
var now = []; // Items we're executing now
// A flag so we know if we should create a fallback timeout to catch the tail
// of the event
var pending = false;
function flush() {
// later has become now!
var temp = now;
now = later;
later = temp;
// Flush it!
for (var i = 0, l = now.length; i < l; i++) {
var callback = now[i];
callback();
}
now.length = 0;
}
// Keep flushing till there is nothing left
function loop() {
while (later.length) {
flush()
}
pending = false;
}
// Public //
// Queue up a callback to be executed at the end of the current tick
// Multiple calls to this within a single tick will be executed sequentially
// Calls to this within those calls will be grouped after the first group
function nextTick(callback) {
later.push(callback)
if (!pending) {
setTimeout(loop, 0);
pending = true;
}
}
// A hook for frameworks that have access to the event-source
// This is better when possible to avoid the unneeded setTimeout 0 hack
function source(next) {
pending = true;
next();
loop();
}
// Expose the two public functions
return {
nextTick: nextTick,
source: source
};
}
var loop = makeLoop();
// Test to make sure callbacks set up during a callback get grouped to the next
// virtual tick.
console.log("Before");
loop.source(function () {
loop.nextTick(function () {
console.log("cool stuff1");
loop.nextTick(function () {
console.log("cool stuff4");
loop.nextTick(function () {
console.log("cool stuff7");
});
});
});
loop.nextTick(function () {
console.log("cool stuff2");
loop.nextTick(function () {
console.log("cool stuff5");
loop.nextTick(function () {
console.log("cool stuff8");
});
});
});
loop.nextTick(function () {
console.log("cool stuff3");
loop.nextTick(function () {
console.log("cool stuff6");
loop.nextTick(function () {
console.log("cool stuff9");
});
});
});
});
console.log("After");
// Test to make sure our algorithm won't grow the stack with each iteration.
console.log("A million virtual ticks!");
loop.source(function () {
var i = 1000000;
function infinite() {
if (--i) {
loop.nextTick(infinite);
}
}
loop.nextTick(infinite);
});
console.log("Done");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment