New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

async-listener

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-listener - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

181

glue.js
var wrap = require('shimmer').wrap;
/**
* There is one list of currently active listeners that is mutated in place by
* addAsyncListener and removeAsyncListener. This complicates error-handling,
* for reasons that are discussed below.
*/
var listeners = [];
/**
* There can be multiple listeners with the same properties, so disambiguate
* them by assigning them an ID at creation time.
*/
var uid = 0;
/**
* Ensure that errors coming from within listeners are handed off to domains,
* process._fatalException, or uncaughtException without being treated like
* user errors.
*/
var inAsyncTick = false;
/**
* Error handlers on listeners can throw, the the catcher needs to be able to
* discriminate between exceptions thrown by user code, and exceptions coming
* from within the catcher itself. Use a global to keep track of which state
* the catcher is currently in.
*/
var inErrorTick = false;
/**
* Throwing always happens synchronously. If the current array of values for

@@ -12,12 +37,29 @@ * the current list of asyncListeners is put in a module-scoped variable right

*/
var errorData = null;
var inAsyncTick = false, inErrorTick = false;
function asyncErrorHandler(er) {
if (inErrorTick) return false;
if (!listeners || listeners.length === 0) return false;
var errorValues;
/**
* Because asynchronous contexts can be nested, and errors can come from anywhere
* in the stack, a little extra work is required to keep track of where in the
* nesting we are. Because JS arrays are frequently mutated in place
*/
var listenerStack = [];
/**
* The error handler on a listener can capture errors thrown during synchronous
* execution immediately after the listener is added. To capture both
* synchronous and asynchronous errors, the error handler just uses the
* "global" list of active listeners, and the rest of the code ensures that the
* listener list is correct by using a stack of listener lists during
* asynchronous execution.
*/
function asyncCatcher(er) {
var length = listeners.length;
if (inErrorTick || length === 0) return false;
var handled = false;
/*
* error handlers
*/
inErrorTick = true;
var length = listeners.length;
for (var i = 0; i < length; ++i) {

@@ -27,3 +69,3 @@ if (!listeners[i].callbacks) continue;

var error = listeners[i].callbacks.error;
var value = errorData && errorData[i];
var value = errorValues && errorValues[i];
if (typeof error === 'function') handled = error(value, er) || handled;

@@ -33,21 +75,64 @@ }

/* Test whether there are any listener arrays on the stack. In the case of
* synchronous throws when the listener is active, there may have been
* none pushed yet.
*/
if (listenerStack.length > 0) listeners = listenerStack.pop();
errorValues = undefined;
return handled && !inAsyncTick;
}
// 0.9+
if (process._fatalException) {
wrap(process, '_fatalException', function (_fatalException) {
return function _asyncFatalException(er) {
return asyncErrorHandler(er) || _fatalException(er);
return asyncCatcher(er) || _fatalException(er);
};
});
}
// 0.8 and below
else {
// will be the first to fire if async-listener is the first module loaded
process.on('uncaughtException', function _asyncUncaughtException(er) {
return asyncErrorHandler(er) || false;
return asyncCatcher(er) || false;
});
}
/**
* Simple helper function that's probably faster than using Array
* filter methods and can be inlined.
*/
function union(dest, destLength, added, addedLength) {
var returned = [];
if (destLength === 0 && addedLength === 0) return returned;
for (var j = 0; j < destLength; j++) returned[j] = dest[j];
if (addedLength === 0) return returned;
for (var i = 0; i < addedLength; i++) {
var missing = true;
for (j = 0; j < destLength; j++) {
if (dest[j].uid === added[i].uid) {
missing = false;
break;
}
}
if (missing) returned.push(added[i]);
}
return returned;
}
/**
* The guts of the system -- called each time an asynchronous event happens
* while one or more listeners are active.
*/
function asyncWrap(original, list, length) {
var data = [];
var values = [];
/*
* listeners
*/
inAsyncTick = true;

@@ -58,29 +143,56 @@ for (var i = 0; i < length; ++i) {

*/
data[i] = list[i].domain;
values[i] = list[i].domain;
var value = list[i].listener.call(this);
if (typeof value !== 'undefined') data[i] = value;
if (typeof value !== 'undefined') values[i] = value;
}
inAsyncTick = false;
/* One of the main differences between this polyfill and the core
* asyncListener support is that core avoids creating closures by putting a
* lot of the state managemnt on the C++ side of Node (and of course also it
* bakes support for async listeners into the Node C++ API through the
* AsyncWrap class, which means that it doesn't monkeypatch basically every
* async method like this does).
*/
return function () {
/*
* before handlers
*/
inAsyncTick = true;
for (var i = 0; i < length; ++i) {
var before = list[i].callbacks && list[i].callbacks.before;
if (before) before(this, data[i]);
if (typeof before === 'function') before(this, values[i]);
}
inAsyncTick = false;
// stash for error handling
errorData = data;
listeners = list.slice();
// put the current values where the catcher can see them
errorValues = values;
/* More than one listener can end up inside these closures, so save the
* current listeners on a stack.
*/
listenerStack.push(listeners);
/* Activate both the listeners that were active when the closure was
* created and the listeners that were previously active.
*/
listeners = union(list, length, listeners, listeners.length);
// save the return value to pass to the after callbacks
var returned = original.apply(this, arguments);
// back to the previous listener list on the stack
listeners = listenerStack.pop();
errorValues = undefined;
/*
* after handlers (not run if original throws)
*/
inAsyncTick = true;
for (i = 0; i < length; ++i) {
var after = list[i].callbacks && list[i].callbacks.after;
if (after) after(this, data[i], returned);
if (typeof after === 'function') after(this, values[i], returned);
}
inAsyncTick = false;
return returned;

@@ -90,10 +202,37 @@ };

function noWrap(original, list, length) {
// for performance in the case where there are no handlers, just the listener
function simpleWrap(original, list, length) {
inAsyncTick = true;
for (var i = 0; i < length; ++i) list[i].listener();
return original;
inAsyncTick = false;
// still need to make sure nested async calls are made in the context
// of the listeners active at their creation
return function () {
listenerStack.push(listeners);
listeners = union(list, length, listeners, listeners.length);
var returned = original.apply(this, arguments);
listeners = listenerStack.pop();
return returned;
};
}
/**
* Called each time an asynchronous function that's been monkeypatched in
* index.js is called. If there are no listeners, return the function
* unwrapped. If there are any asyncListeners and any of them have callbacks,
* pass them off to asyncWrap for later use, otherwise just call the listener.
*/
function wrapCallback(original) {
var length = listeners.length;
// no context to capture, so avoid closure creation
if (length === 0) return original;
// capture the active listeners as of when the wrapped function was called
var list = listeners.slice();
var length = list.length;
for (var i = 0; i < length; ++i) {

@@ -103,3 +242,3 @@ if (list[i].callbacks) return asyncWrap(original, list, length);

return noWrap(original, list, length);
return simpleWrap(original, list, length);
}

@@ -106,0 +245,0 @@

2

package.json
{
"name": "async-listener",
"version": "0.3.0",
"version": "0.4.0",
"description": "Polyfill exporting trevnorris's 0.11+ asyncListener API.",

@@ -5,0 +5,0 @@ "author": "Forrest L Norvell <ogd@aoaioxxysz.net>",

@@ -54,2 +54,3 @@ // Copyright Joyent, Inc. and other Node contributors.

var listener = process.createAsyncListener(onAsync);
var listener2 = process.createAsyncListener(onAsync);

@@ -134,3 +135,3 @@

addListener(listener);
addListener(listener);
addListener(listener2);

@@ -144,3 +145,3 @@ setTimeout(function() {

removeListener(listener);
removeListener(listener);
removeListener(listener2);
});

@@ -147,0 +148,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc