Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add smart stack traces + easy future chaining

When throwing through a Future, this captures the stack trace for each
future so you can show a full stack trace while debugging.

Additionally this makes resolve() kind of magic, where if the first
parameter is a future, any errors will be forwarded to the future, and
the callback's signature will be changed to function(val){} from
function(err, val){}.
  • Loading branch information...
commit 5f7a0f5ce7f0b0f37b5f8163b561fbed7128b014 1 parent c4dfaff
@laverdet authored
Showing with 49 additions and 6 deletions.
  1. +49 −6 future.js
View
55 future.js
@@ -120,7 +120,27 @@ Future.prototype = {
if (!this.resolved) {
throw new Error('Future must resolve before value is ready');
} else if (this.error) {
- throw this.error;
+ // Link the stack traces up
+ var stack = {}, error = this.error instanceof Object ? this.error : new Error(this.error);
+ var longError = Object.create(error);
+ Error.captureStackTrace(stack, Future.prototype.get);
+ Object.defineProperty(longError, 'stack', {
+ get: function() {
+ var baseStack = error.stack;
+ if (baseStack) {
+ baseStack = baseStack.split('\n');
+ return [baseStack[0]]
+ .concat(stack.stack.split('\n').slice(1))
+ .concat(' - - - - -')
+ .concat(baseStack.slice(1))
+ .join('\n');
+ } else {
+ return stack.stack;
+ }
+ },
+ enumerable: true,
+ });
+ throw longError;
} else {
return this.value;
}
@@ -141,7 +161,12 @@ Future.prototype = {
delete this.callbacks;
for (var ii = 0; ii < callbacks.length; ++ii) {
try {
- callbacks[ii](undefined, value);
+ var ref = callbacks[ii];
+ if (ref[1]) {
+ ref[1](value);
+ } else {
+ ref[0](undefined, value);
+ }
} catch(ex) {
console.log(String(ex.stack || ex.message || ex));
process.exit(1);
@@ -167,7 +192,12 @@ Future.prototype = {
delete this.callbacks;
for (var ii = 0; ii < callbacks.length; ++ii) {
try {
- callbacks[ii](error);
+ var ref = callbacks[ii];
+ if (ref[1]) {
+ ref[0].throw(error);
+ } else {
+ ref[0](error);
+ }
} catch(ex) {
console.log(ex.stack || ex);
process.exit(1);
@@ -198,12 +228,25 @@ Future.prototype = {
/**
* Waits for this future to resolve and then invokes a callback.
+ *
+ * If two arguments are passed, the first argument is a future which will be thrown to in the case
+ * of error, and the second is a function(val){} callback.
+ *
+ * If only one argument is passed it is a standard function(err, val){} callback.
*/
- resolve: function(cb) {
+ resolve: function(arg1, arg2) {
if (this.resolved) {
- cb(this.error, this.value);
+ if (arg2) {
+ if (this.error) {
+ arg1.throw(this.error);
+ } else {
+ arg2(this.value);
+ }
+ } else {
+ arg1(this.error, this.value);
+ }
} else {
- (this.callbacks = this.callbacks || []).push(cb);
+ (this.callbacks = this.callbacks || []).push([arg1, arg2]);
}
return this;
},

0 comments on commit 5f7a0f5

Please sign in to comment.
Something went wrong with that request. Please try again.