Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add the number of traversed items in end and both events, new propert…

…y".errors" for multiple errors
  • Loading branch information...
commit 703ae25ef06e9171bd4a8447381a5593acb0f611 1 parent ed4a425
@wdavidw authored
View
33 doc/index.md
@@ -90,16 +90,26 @@ The `each` function signature is: `each(subject)`.
The return object is an instance of `EventEmitter`.
-The following properties and functions are available:
+The following properties are available:
+- `paused`
+ Indicate the state of the current event emitter.
+- `readable`
+ Indicate if the stream will emit more event.
+- `started`
+ Number of callbacks which have been called.
+- `done`
+ Number of callbacks which have finished.
+
+The following functions are available:
- `parallel`
The second argument is optional and indicate wether or not you want the
iteration to run in `sequential`, `parallel` or `concurrent` mode. See below
for more details about the different modes.
-- `paused`
- Indicate the state of the current event emitter
-- `readable`
- Indicate if the stream will emit more event
+- `times`
+ Repeat operation multiple times.
+- `files`
+ Emit file paths based on a directory or globbing expression.
The following events are emitted:
@@ -113,12 +123,10 @@ The following events are emitted:
an error object as its first argument and eventually a second argument. See
the `dealing with errors` section for more information.
- `end`
- Called only if all the callback have been handled successfully. No argument is
- provided in the callback.
+ Called only if all the callback have been handled successfully. The total number of traversed item is provided in the callback as the first argument.
- `both`
Called only once all the items have been handled. It is a conveniency event
- combining the `error` and `end` event in one call. Return the same arguments
- than the `error` or `end` events depending on the operation outturn.
+ combining the `error` and `end` event in one call. Return the error object if any as a first argument and the number of traversed items as the second argument. In case of an error, this number correspond to the number of item callbacks which called next.
Parallelization modes
---------------------
@@ -183,10 +191,9 @@ iteration will be stoped. Note that in case of parallel and concurrent mode,
the current callbacks are not canceled but no new element will be send to the
`item` event.
-The first element send to the `error` event is an error instance. In
-`sequential` mode, it is the event sent in the previous item `callback`. In
-`parallel` and `concurrent` modes, the second argument is an array will all
-the error sent since multiple errors may be thrown at the same time.
+The first argument passed to the `error` event callback is an error instance. In
+`sequential` mode, it is always the error that was thrown by the failed item callback. In
+`parallel` and `concurrent` modes, there may be more than one event thrown asynchrously. In such case, the error has a generic message such as "Multiple error #{number of errors}" and the property ".errors" give access to each individual error.
Traversing an array
-------------------
View
16 lib/each.js
@@ -98,21 +98,23 @@ module.exports = function(elements) {
return eacher;
};
run = function() {
- var args, emit, emitError, index, lboth, lerror, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3;
+ var args, emit, emitError, error, index, lboth, lerror, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3;
if (eacher.paused) {
return;
}
+ error = null;
if (endable === 1 && (eacher.done === eacher.total * times || (errors.length && eacher.started === eacher.done))) {
eacher.readable = false;
if (errors.length) {
if (parallel !== 1) {
if (errors.length === 1) {
- args = [errors[0], errors];
+ error = errors[0];
} else {
- args = [new Error("Multiple errors (" + errors.length + ")"), errors];
+ error = new Error("Multiple errors (" + errors.length + ")");
+ error.errors = errors;
}
} else {
- args = [errors[0]];
+ error = errors[0];
}
lerror = events.error.length;
lboth = events.both.length;
@@ -121,7 +123,7 @@ module.exports = function(elements) {
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
emit = _ref[_i];
if (emitError) {
- emit.apply(null, args);
+ emit(error);
}
}
} else {
@@ -129,13 +131,13 @@ module.exports = function(elements) {
_ref1 = events.end;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
emit = _ref1[_j];
- emit();
+ emit(eacher.done);
}
}
_ref2 = events.both;
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
emit = _ref2[_k];
- emit.apply(null, args);
+ emit(error, eacher.done);
}
return;
}
View
15 src/each.coffee
@@ -74,23 +74,26 @@ module.exports = (elements) ->
run = () ->
return if eacher.paused
# This is the end
+ error = null
if endable is 1 and (eacher.done is eacher.total * times or (errors.length and eacher.started is eacher.done) )
eacher.readable = false
if errors.length
if parallel isnt 1
if errors.length is 1
- then args = [errors[0], errors]
- else args = [new Error("Multiple errors (#{errors.length})"), errors]
+ then error = errors[0]
+ else
+ error = new Error("Multiple errors (#{errors.length})")
+ error.errors = errors
else
- args = [errors[0]]
+ error = errors[0]
lerror = events.error.length
lboth = events.both.length
emitError = lerror or (not lerror and not lboth)
- for emit in events.error then emit args... if emitError
+ for emit in events.error then emit error if emitError
else
args = []
- for emit in events.end then emit()
- for emit in events.both then emit args...
+ for emit in events.end then emit eacher.done
+ for emit in events.both then emit error, eacher.done
return
return if errors.length isnt 0
while (if parallel is true then (eacher.total * times - eacher.started) > 0 else Math.min( (parallel - eacher.started + eacher.done), (eacher.total * times - eacher.started) ) )
View
14 test/callback.coffee
@@ -9,20 +9,20 @@ describe 'Callback', ->
.on 'item', (next) ->
arguments.length.should.eql 1
next()
- .on 'end', next
+ .on 'end', -> next()
it 'should provide element and next argument', (next) ->
each( [ 'a', 'b', 'c' ] )
.on 'item', (element, next) ->
['a', 'b', 'c'].should.include element
next()
- .on 'end', next
+ .on 'end', -> next()
it 'should provide element, index and next argument', (next) ->
each( [ 'a', 'b', 'c' ] )
.on 'item', (element, index, next) ->
['a', 'b', 'c'].should.include element
index.should.be.a 'number'
next()
- .on 'end', next
+ .on 'end', -> next()
it 'throw error with no argument', (next) ->
each( ['a', 'b', 'c'] )
.on 'item', () ->
@@ -36,20 +36,20 @@ describe 'Callback', ->
.on 'item', (next) ->
arguments.length.should.eql 1
next()
- .on 'end', next
+ .on 'end', -> next()
it 'should provide value and next argument', (next) ->
each( {a: 1, b: 2, c: 3} )
.on 'item', (value, next) ->
value.should.be.a 'number'
next()
- .on 'end', next
+ .on 'end', -> next()
it 'should provide key, value and next argument', (next) ->
each( {a: 1, b: 2, c: 3} )
.on 'item', (key, value, next) ->
['a', 'b', 'c'].should.include key
value.should.be.a 'number'
next()
- .on 'end', next
+ .on 'end', -> next()
it 'should provide key, value, index and next argument', (next) ->
each( {a: 1, b: 2, c: 3} )
.on 'item', (key, value, counter, next) ->
@@ -57,7 +57,7 @@ describe 'Callback', ->
value.should.be.a 'number'
counter.should.be.a 'number'
next()
- .on 'end', next
+ .on 'end', -> next()
it 'throw error with no argument', (next) ->
each( {a: 1, b: 2, c: 3} )
.on 'item', () ->
View
66 test/error.coffee
@@ -6,12 +6,12 @@ describe 'Error', ->
it 'Concurrent # error and both callbacks', (next) ->
current = 0
error_called = false
- error_assert = (err, errs) ->
+ error_assert = (err) ->
current.should.eql 9
err.message.should.eql 'Multiple errors (2)'
- errs.length.should.eql 2
- errs[0].message.should.eql 'Testing error in 6'
- errs[1].message.should.eql 'Testing error in 7'
+ err.errors.length.should.eql 2
+ err.errors[0].message.should.eql 'Testing error in 6'
+ err.errors[1].message.should.eql 'Testing error in 7'
each( [ {id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}, {id: 7}, {id: 8}, {id: 9}, {id: 10}, {id: 11} ] )
.parallel( 4 )
.on 'item', (element, index, next) ->
@@ -23,23 +23,22 @@ describe 'Error', ->
else
next()
, 100
- .on 'error', (err, errs) ->
- error_assert.call null, err, errs
+ .on 'error', (err) ->
+ error_assert err
error_called = true
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
assert.ok false
- .on 'both', (err, errs) ->
+ .on 'both', (err) ->
error_called.should.be.ok
- error_assert.call null, err, errs
+ error_assert err
next()
it 'Concurrent # throw error', (next) ->
current = 0
error_called = false
- error_assert = (err, errs) ->
+ error_assert = (err) ->
current.should.eql 6
err.message.should.eql 'Testing error in 6'
- errs.length.should.eql 1
- errs[0].message.should.eql 'Testing error in 6'
+ should.not.exists err.errors
each( [ {id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}, {id: 7}, {id: 8}, {id: 9}, {id: 10}, {id: 11} ] )
.parallel( 4 )
.on 'item', (element, index, next) ->
@@ -49,14 +48,14 @@ describe 'Error', ->
throw new Error "Testing error in #{element.id}"
else
next()
- .on 'error', (err, errs) ->
- error_assert.call null, err, errs
+ .on 'error', (err) ->
+ error_assert err
error_called = true
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
assert.ok false
- .on 'both', (err, errs) ->
+ .on 'both', (err) ->
error_called.should.be.ok
- error_assert.call null, err, errs
+ error_assert err
next()
it 'Parallel # multiple errors # error callback', (next) ->
# when multiple errors are thrown, a new error object is created
@@ -75,13 +74,13 @@ describe 'Error', ->
else
next()
, 100
- .on 'error', (err, errs) ->
+ .on 'error', (err) ->
err.message.should.eql 'Multiple errors (2)'
- errs.length.should.eql 2
- errs[0].message.should.eql 'Testing error in 1'
- errs[1].message.should.eql 'Testing error in 3'
+ err.errors.length.should.eql 2
+ err.errors[0].message.should.eql 'Testing error in 1'
+ err.errors[1].message.should.eql 'Testing error in 3'
return next()
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
false.should.be.ok
it 'Parallel # single error # error callback', (next) ->
# when on one error is thrown, the error is passed to
@@ -99,12 +98,10 @@ describe 'Error', ->
else
next()
, 100
- .on 'error', (err, errs) ->
+ .on 'error', (err) ->
err.message.should.eql 'Testing error in 3'
- errs.length.should.eql 1
- errs[0].message.should.eql 'Testing error in 3'
return next()
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
false.should.be.ok
it 'Parallel # async # both callback', (next) ->
current = 0
@@ -119,13 +116,13 @@ describe 'Error', ->
else
next()
, 100
- .on 'both', (err, errs) ->
+ .on 'both', (err) ->
err.message.should.eql 'Multiple errors (2)'
- errs.length.should.eql 2
- errs[0].message.should.eql 'Testing error in 1',
- errs[1].message.should.eql 'Testing error in 3'
+ err.errors.length.should.eql 2
+ err.errors[0].message.should.eql 'Testing error in 1',
+ err.errors[1].message.should.eql 'Testing error in 3'
return next()
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
false.should.be.ok
it 'Parallel # sync # both callback', (next) ->
current = 0
@@ -137,12 +134,11 @@ describe 'Error', ->
if element.id is 1 or element.id is 3
next( new Error "Testing error in #{element.id}" )
else setTimeout next, 100
- .on 'both', (err, errs) ->
+ .on 'both', (err) ->
# In this specific case, since the item handler
# send error sequentially, we are only receiving
# one error
err.message.should.eql 'Testing error in 1'
- errs.length.should.eql 1
next()
it 'Sequential # sync # error callback', (next) ->
current = 0
@@ -156,7 +152,7 @@ describe 'Error', ->
.on 'error', (err) ->
err.message.should.eql 'Testing error'
next()
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
false.should.be.ok
it 'Sequential # async # error callback', (next) ->
current = 0
@@ -172,6 +168,6 @@ describe 'Error', ->
.on 'error', (err) ->
err.message.should.eql 'Testing error'
next()
- .on 'end', (err, errs) ->
+ .on 'end', (err) ->
false.should.be.ok
Please sign in to comment.
Something went wrong with that request. Please try again.