Created
June 21, 2011 05:56
-
-
Save creationix/1037316 to your computer and use it in GitHub Desktop.
Userspace EventLoop for JavaScript
This file contains hidden or 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
// 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 | |
}; | |
} |
This file contains hidden or 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
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