diff --git a/src/node.js b/src/node.js index 82a5937e2e..f329c0055c 100644 --- a/src/node.js +++ b/src/node.js @@ -49,9 +49,17 @@ var nextTickQueue = []; process._tickCallback = function () { var l = nextTickQueue.length; if (l === 0) return; - for (var i = 0; i < l; i++) { - nextTickQueue[i](); + + try { + for (var i = 0; i < l; i++) { + nextTickQueue[i](); + } } + catch(e) { + nextTickQueue.splice(0, i+1); + throw e; + } + nextTickQueue.splice(0, l); }; diff --git a/test/simple/test-next-tick-errors.js b/test/simple/test-next-tick-errors.js new file mode 100644 index 0000000000..421baa999a --- /dev/null +++ b/test/simple/test-next-tick-errors.js @@ -0,0 +1,41 @@ +common = require("../common"); +assert = common.assert + +var order = [], + exceptionHandled = false; + +// This nextTick function will throw an error. It should only be called once. +// When it throws an error, it should still get removed from the queue. +process.nextTick(function() { + order.push('A'); + // cause an error + what(); +}); + +// This nextTick function should remain in the queue when the first one +// is removed. +process.nextTick(function() { + order.push('C'); +}); + +process.addListener('uncaughtException', function() { + if (!exceptionHandled) { + exceptionHandled = true; + order.push('B'); + // We call process.nextTick here to make sure the nextTick queue is + // processed again. If everything goes according to plan then when the queue + // gets ran there will be two functions with this being the second. + process.nextTick(function() { + order.push('D'); + }); + } + else { + // If we get here then the first process.nextTick got called twice + order.push('OOPS!'); + } +}); + +process.addListener('exit', function() { + assert.deepEqual(['A','B','C','D'], order); +}); +