-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1177 from caolan/map-objects
Mapping over Objects
- Loading branch information
Showing
8 changed files
with
218 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import mapValuesLimit from './mapValuesLimit'; | ||
import doLimit from './internal/doLimit'; | ||
|
||
|
||
/** | ||
* A relative of `map`, designed for use with objects. | ||
* | ||
* Produces a new Object by mapping each value of `obj` through the `iteratee` | ||
* function. The `iteratee` is called each `value` and `key` from `obj` and a | ||
* callback for when it has finished processing. Each of these callbacks takes | ||
* two arguments: an `error`, and the transformed item from `obj`. If `iteratee` | ||
* passes an error to its callback, the main `callback` (for the `mapValues` | ||
* function) is immediately called with the error. | ||
* | ||
* Note, the order of the keys in the result is not guaranteed. The keys will | ||
* be roughly in the order they complete, (but this is very engine-specific) | ||
* | ||
* @name mapValues | ||
* @static | ||
* @memberOf async | ||
* @category Collection | ||
* @param {Object} obj - A collection to iterate over. | ||
* @param {Function} iteratee - A function to apply to each value and key in | ||
* `coll`. The iteratee is passed a `callback(err, transformed)` which must be | ||
* called once it has completed with an error (which can be `null`) and a | ||
* transformed value. Invoked with (value, key, callback). | ||
* @param {Function} [callback] - A callback which is called when all `iteratee` | ||
* functions have finished, or an error occurs. Results is an array of the | ||
* transformed items from the `obj`. Invoked with (err, result). | ||
* @example | ||
* | ||
* async.mapValues({ | ||
* f1: 'file1', | ||
* f2: 'file2', | ||
* f3: 'file3' | ||
* }, fs.stat, function(err, result) { | ||
* // results is now a map of stats for each file, e.g. | ||
* // { | ||
* // f1: [stats for file1], | ||
* // f2: [stats for file2], | ||
* // f3: [stats for file3] | ||
* // } | ||
* }); | ||
*/ | ||
|
||
export default doLimit(mapValuesLimit, Infinity); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import eachOfLimit from './eachOfLimit'; | ||
|
||
/** | ||
* The same as `mapValues` but runs a maximum of `limit` async operations at a | ||
* time. | ||
* | ||
* @name mapValuesLimit | ||
* @static | ||
* @memberOf async | ||
* @see async.mapValues | ||
* @category Collection | ||
* @param {Object} obj - A collection to iterate over. | ||
* @param {number} limit - The maximum number of async operations at a time. | ||
* @param {Function} iteratee - A function to apply to each value in `obj`. | ||
* The iteratee is passed a `callback(err, transformed)` which must be called | ||
* once it has completed with an error (which can be `null`) and a | ||
* transformed value. Invoked with (value, key, callback). | ||
* @param {Function} [callback] - A callback which is called when all `iteratee` | ||
* functions have finished, or an error occurs. Result is an object of the | ||
* transformed values from the `obj`. Invoked with (err, result). | ||
*/ | ||
export default function mapValuesLimit(obj, limit, iteratee, callback) { | ||
var newObj = {}; | ||
eachOfLimit(obj, limit, function(val, key, next) { | ||
iteratee(val, key, function (err, result) { | ||
if (err) return next(err); | ||
newObj[key] = result; | ||
next(); | ||
}); | ||
}, function (err) { | ||
callback(err, newObj); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import mapValuesLimit from './mapValuesLimit'; | ||
import doLimit from './internal/doLimit'; | ||
|
||
/** | ||
* The same as `mapValues` but runs only a single async operation at a time. | ||
* | ||
* @name mapValuesSeries | ||
* @static | ||
* @memberOf async | ||
* @see async.mapValues | ||
* @category Collection | ||
* @param {Object} obj - A collection to iterate over. | ||
* @param {Function} iteratee - A function to apply to each value in `obj`. | ||
* The iteratee is passed a `callback(err, transformed)` which must be called | ||
* once it has completed with an error (which can be `null`) and a | ||
* transformed value. Invoked with (value, key, callback). | ||
* @param {Function} [callback] - A callback which is called when all `iteratee` | ||
* functions have finished, or an error occurs. Result is an object of the | ||
* transformed values from the `obj`. Invoked with (err, result). | ||
*/ | ||
export default doLimit(mapValuesLimit, 1); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
var async = require('../lib'); | ||
var expect = require('chai').expect; | ||
var assert = require('assert'); | ||
|
||
describe('mapValues', function () { | ||
var obj = {a: 1, b: 2, c: 3}; | ||
|
||
context('mapValuesLimit', function () { | ||
it('basics', function (done) { | ||
var running = 0; | ||
var concurrency = { | ||
a: 2, | ||
b: 2, | ||
c: 1 | ||
}; | ||
async.mapValuesLimit(obj, 2, function (val, key, next) { | ||
running++; | ||
async.setImmediate(function () { | ||
expect(running).to.equal(concurrency[key]); | ||
running--; | ||
next(null, key + val); | ||
}); | ||
}, function (err, result) { | ||
expect(running).to.equal(0); | ||
expect(err).to.eql(null); | ||
expect(result).to.eql({a: 'a1', b: 'b2', c: 'c3'}); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('error', function (done) { | ||
async.mapValuesLimit(obj, 1, function(val, key, next) { | ||
if (key === 'b') { | ||
return next(new Error("fail")); | ||
} | ||
next(null, val); | ||
}, function (err, result) { | ||
expect(err).to.not.eql(null); | ||
expect(result).to.eql({a: 1}); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
|
||
context('mapValues', function () { | ||
it('basics', function (done) { | ||
var running = 0; | ||
var concurrency = { | ||
a: 3, | ||
b: 2, | ||
c: 1 | ||
}; | ||
async.mapValues(obj, function (val, key, next) { | ||
running++; | ||
async.setImmediate(function () { | ||
expect(running).to.equal(concurrency[key]); | ||
running--; | ||
next(null, key + val); | ||
}); | ||
}, function (err, result) { | ||
expect(running).to.equal(0); | ||
expect(err).to.eql(null); | ||
expect(result).to.eql({a: 'a1', b: 'b2', c: 'c3'}); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
|
||
context('mapValuesSeries', function () { | ||
it('basics', function (done) { | ||
var running = 0; | ||
var concurrency = { | ||
a: 1, | ||
b: 1, | ||
c: 1 | ||
}; | ||
async.mapValuesSeries(obj, function (val, key, next) { | ||
running++; | ||
async.setImmediate(function () { | ||
expect(running).to.equal(concurrency[key]); | ||
running--; | ||
next(null, key + val); | ||
}); | ||
}, function (err, result) { | ||
expect(running).to.equal(0); | ||
expect(err).to.eql(null); | ||
expect(result).to.eql({a: 'a1', b: 'b2', c: 'c3'}); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |
872cb91
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the behaviour there I give an object and get an array back! See #1133
Maybe then we need another map function for objects.
872cb91
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's exactly what
mapValues
does, which this PR adds.872cb91
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, looks like the thing I need. I just tried it out and work's for me like a charm.
Still the documentation is missing.