Browse files

Add `callbackLocation` property to an err object

  • Loading branch information...
1 parent ebe8ce2 commit beee8309b9ba7624661d593a3390dfb9477c5566 @nakamura-to committed Mar 19, 2012
Showing with 67 additions and 7 deletions.
  1. +23 −1 README.md
  2. +5 −2 examples/{errorHandle.js → errorHandling.js}
  3. +25 −3 lib/gate.js
  4. +14 −1 test/gate.js
View
24 README.md
@@ -64,7 +64,8 @@ Wraps a value to distinguish between a value as argument and a mapping index.
Awaits all asynchronous calls completion and then runs a `callback`.
* `callback`: Required. A callback to run after all asynchronous calls completion.
-* `err`: Required. An error to indicate any asynhronous calls are failed.
+* `err`: Required. An error to indicate any asynhronous calls are failed.
+If the `err` is `object` type, it have a property `callbackLocation` to tell you which async call is related the `err`.
* `results`: Required. An array to contain each asynchronous call result as element.
## More Examples
@@ -125,6 +126,27 @@ process.nextTick(function () {
});
```
+### Error Handling
+
+Check `err.callbackLocation` at an await callback to know which async call is related the `err`.
+
+```js
+var gate = require('gate');
+var fs = require('fs');
+
+var latch = gate.latch();
+fs.readFile('file1', 'utf8', latch({name: 'file1', data: 1}));
+fs.readFile('non-existent', 'utf8', latch({name: 'non-existent', data: 1}));
+
+latch.await(function (err, results) {
+ if (err) {
+ console.log(err + ', callbackLocation: ' + err.callbackLocation);
+ } else {
+ console.log(results);
+ }
+});
+```
+
### Error Check Skipping
Pass `true` as 2nd argument to a function being returned from `gate.latch()`.
View
7 examples/errorHandle.js → examples/errorHandling.js
@@ -6,6 +6,9 @@ fs.readFile('file1', 'utf8', latch({name: 'file1', data: 1}));
fs.readFile('non-existent', 'utf8', latch({name: 'non-existent', data: 1}));
latch.await(function (err, results) {
- if (err) throw err;
- console.log(results);
+ if (err) {
+ console.log(err + ', callbackLocation: ' + err.callbackLocation);
+ } else {
+ console.log(results);
+ }
});
View
28 lib/gate.js
@@ -2,13 +2,14 @@
exports.latch = latch;
+var util = require('util');
var assert = require('assert');
var noop = function noop() {};
function latch(count) {
var async = new Async(count);
var _latch = function makeCallback(mapping, skipErrorCheck) {
- return async.makeCallback(mapping, skipErrorCheck);
+ return async.makeCallback(makeCallback, mapping, skipErrorCheck);
};
_latch.val = function val(value) {
return new Val(value);
@@ -47,20 +48,24 @@ Async.prototype.await = function await(callback) {
}
};
-Async.prototype.makeCallback = function makeCallback(mapping, skipErrorCheck) {
+Async.prototype.makeCallback = function makeCallback(caller, mapping, skipErrorCheck) {
var type = typeof mapping;
assert(type !== 'undefined' || type !== 'number' || type !== 'object',
'An argument `mapping` must be a number or an object, if specified.');
if (this.count === 0) return noop;
if (this.count > 0) this.count--;
this.pending++;
var index = this.index++;
+ var location = getLocation(caller);
var self = this;
- return function asyncCallback(error) {
+ return function callback(error) {
var next = self.next;
self.pending--;
if (!self.canceled) {
+ if (error && typeof error === 'object' && !('callbackLocation' in error)) {
+ error.callbackLocation = location;
+ }
if (error && !skipErrorCheck) {
self.canceled = true;
if (next) {
@@ -94,4 +99,21 @@ Async.prototype.makeCallback = function makeCallback(mapping, skipErrorCheck) {
return result;
}, {});
}
+
+ function getLocation(target) {
+ var originalPrepareStackTrace = Error.prepareStackTrace;
+ var originalStackTraceLimit = Error.stackTraceLimit;
+ Error.prepareStackTrace = prepareStackTrace;
+ Error.stackTraceLimit = 1;
+ var err = {};
+ Error.captureStackTrace(err, target);
+ var stack = err.stack;
+ Error.prepareStackTrace = originalPrepareStackTrace;
+ Error.stackTraceLimit = originalStackTraceLimit;
+ return util.format('%s:%d:%d', stack.getFileName(), stack.getLineNumber(), stack.getColumnNumber());
+
+ function prepareStackTrace() {
+ return arguments[1][0];
+ }
+ }
};
View
15 test/gate.js
@@ -64,12 +64,25 @@ describe('latch', function() {
process.nextTick(function () {
callback('ERROR');
});
- latch.await(function (err) {
+ latch.await(function (err) {
assert.strictEqual('ERROR', err);
done();
});
});
+ it('should handle error object', function (done) {
+ var latch = gate.latch();
+ var callback = latch(1);
+ process.nextTick(function () {
+ callback(new Error('ERROR'));
+ });
+ latch.await(function (err) {
+ assert.strictEqual('ERROR', err.message);
+ assert(err.callbackLocation);
+ done();
+ });
+ });
+
it('should skip error check', function (done) {
var latch = gate.latch();
var callback = latch(0, true);

0 comments on commit beee830

Please sign in to comment.