Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: regality/node
...
head fork: regality/node
Checking mergeability… Don’t worry, you can still create the pull request.
  • 6 commits
  • 4 files changed
  • 2 commit comments
  • 1 contributor
Showing with 128 additions and 16 deletions.
  1. +37 −0 doc/api/events.markdown
  2. +51 −1 lib/events.js
  3. +31 −15 lib/timers.js
  4. +9 −0 src/node.js
View
37 doc/api/events.markdown
@@ -93,3 +93,40 @@ Execute each of the listeners in order with the supplied arguments.
* `listener` {Function} The event handler function
This event is emitted any time someone adds a new listener.
+
+## Event Handlers
+
+### setEventHandler(callback)
+
+Pushes onto the event handler stack. When an EventEmitter is
+constructed, it there is a handler on the top of the stack, it will pass
+any uncaught exceptions to that handler.
+
+It will also push that handler onto the stack any time it emits. This
+causes and EventEmitters that are constructed in the emit stack, to
+inherit the same handler.
+
+ function myHandler(err) {
+ console.log('oh noes');
+ }
+
+ setEventHandler(myHandler);
+
+ setTimeout(function() {
+ require('fs').readFile('non-existant-file', function(err, data) {
+ if (err) throw err; // will be sent to myHandler
+ console.log(data);
+ });
+ }, 100);
+
+ clearEventHandler();
+
+ require('fs').readFile('non-existant-file', function(err, data) {
+ if (err) throw err; // will be an uncaught exception and end the process
+ console.log(data);
+ });
+
+### clearEventHandler(callback)
+
+Pops the event handler stack.
+
View
52 lib/events.js
@@ -19,9 +19,41 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+var eventHandlers = []; // event handlers stack
+
+// push onto the handlers stack
+function setEventHandler(handler) {
+ eventHandlers.push(handler);
+}
+
+// pop the handlers stack
+function clearEventHandler() {
+ eventHandlers.pop();
+}
+
+// get top item in stack, if one exists
+function getEventHandler() {
+ return ( eventHandlers.length > 0
+ ? eventHandlers[eventHandlers.length - 1]
+ : null );
+}
+
+// remove all event handlers
+function clearAllEventHandlers() {
+ eventHandlers = [];
+}
+
+exports.setEventHandler = setEventHandler;
+exports.getEventHandler = getEventHandler;
+exports.clearEventHandler = clearEventHandler;
+exports.clearAllEventHandlers = clearAllEventHandlers;
+
var isArray = Array.isArray;
-function EventEmitter() { }
+function EventEmitter() {
+ this.handler = getEventHandler();
+}
+
exports.EventEmitter = EventEmitter;
// By default EventEmitters will print a warning if more than
@@ -38,6 +70,24 @@ EventEmitter.prototype.setMaxListeners = function(n) {
EventEmitter.prototype.emit = function() {
+ if (this.handler) {
+ setEventHandler(this.handler);
+ }
+ try {
+ this._emit.apply(this, arguments);
+ } catch (e) {
+ if (this.handler) {
+ this.handler(e);
+ } else {
+ throw e;
+ }
+ }
+ if (this.handler) {
+ clearEventHandler();
+ }
+};
+
+EventEmitter.prototype._emit = function() {
var type = arguments[0];
// If there is no 'error' event listener then throw.
if (type === 'error') {
View
46 lib/timers.js
@@ -87,18 +87,14 @@ function insert(item, msecs) {
if (!first._onTimeout) continue;
- // v0.4 compatibility: if the timer callback throws and the user's
- // uncaughtException handler ignores the exception, other timers that
- // expire on this tick should still run. If #2582 goes through, this
- // hack should be removed.
+ // We previously caught excpetions here in the case of
+ // an uncaughtExeption handler attached to the process.
+ // This has been removed in favor of using eventHandlers.
//
// https://github.com/joyent/node/issues/2631
- try {
- first._onTimeout();
- } catch (e) {
- if (!process.listeners('uncaughtException').length) throw e;
- process.emit('uncaughtException', e);
- }
+ // https://github.com/joyent/node/issues/2582
+ first._onTimeout();
+
}
}
@@ -156,6 +152,25 @@ exports.active = function(item) {
}
};
+// This method wraps a callback with an event
+// handler if one has been set with setEventHandler()
+function wrapHandler(callback) {
+ var handler = getEventHandler();
+ if (handler) {
+ return function() {
+ setEventHandler(handler);
+ try {
+ callback();
+ } catch (e) {
+ handler(e);
+ }
+ clearEventHandler();
+ }
+ } else {
+ return callback;
+ }
+}
+
/*
* DOM-style timers
@@ -175,7 +190,7 @@ exports.setTimeout = function(callback, after) {
timer._idleNext = timer;
if (arguments.length <= 2) {
- timer._onTimeout = callback;
+ timer._onTimeout = wrapHandler(callback);
} else {
/*
* Sometimes setTimeout is called with arguments, EG
@@ -187,9 +202,10 @@ exports.setTimeout = function(callback, after) {
* desired in the normal case.
*/
var args = Array.prototype.slice.call(arguments, 2);
- timer._onTimeout = function() {
+
+ timer._onTimeout = wrapHandler(function() {
callback.apply(timer, args);
- }
+ });
}
exports.active(timer);
@@ -219,9 +235,9 @@ exports.setInterval = function(callback, repeat) {
}
var args = Array.prototype.slice.call(arguments, 2);
- timer.ontimeout = function() {
+ timer.ontimeout = wrapHandler(function() {
callback.apply(timer, args);
- }
+ });
timer.start(repeat, repeat);
return timer;
View
9 src/node.js
@@ -33,6 +33,7 @@
process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
startup.globalVariables();
+ startup.globalHandlers();
startup.globalTimeouts();
startup.globalConsole();
@@ -161,6 +162,14 @@
global.Buffer = NativeModule.require('buffer').Buffer;
};
+ startup.globalHandlers = function() {
+ var events = NativeModule.require('events');
+ global.setEventHandler = events.setEventHandler;
+ global.getEventHandler = events.getEventHandler;
+ global.clearEventHandler = events.clearEventHandler;
+ global.clearAllEventHandlers = events.clearAllEventHandlers;
+ };
+
startup.globalTimeouts = function() {
global.setTimeout = function() {
var t = NativeModule.require('timers');

Showing you all comments on commits in this comparison.

@cbrammer

Great docs, you should put this in your pull request

Something went wrong with that request. Please try again.