-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding forEachOf to Iterate Objects #168
Conversation
+1 for what you're trying to do here. It would be awesome if async's collection methods were like those in Underscore.js and supported both Objects and Arrays as their primary arguments. My suggestion would be to rework this slightly to incorporate Object directly support into Would also be cool to add Object support to |
I was going back and forth between creating a new function and modifying the existing one. Mostly didn't want to mess with the existing functions to keep from breaking things. But I suppose that's what unit tests are for, so I'll go ahead and make that change. I also figured I would hold off on the other functions like map until it was clear whether or not this would ever land in master. However, it's probably not too much extra work so I'll go ahead and do it. Who knows, it may be more likely to land when it's complete. :) |
Cool. Another idea I had was that you should be able to optionally accept the item key in your iterator. var fruitColors = {"apples": "green", "bananas": "yellow"};
// Outputs:
// green
// yellow
async.forEach(fruitColors, function(value, cb) {
console.log(value);
});
// Outputs:
// apples are green
// bananas are yellow
async.forEach(fruitColors, function(value, key, cb) {
console.log(key + " are " + value);
}); It should be possible to determine whether or not to pass the key by checking the Again this is very much inspired by how Underscore.js works. I might hack on your branch a little if I get time. |
I'd lean towards overloading async.forEach etc too. Although, underscore.js has it easier here since it doesn't need to append a callback to the list of arguments. So we're forced to include the 'key' argument in any iterator definition - though I assume that's going to be the norm when using objects anyway. |
@caolan Why can't we rely on arity to know whether to call
I know Underscore does this, mapping objects to arrays, but it strikes me as strange, like some sort of a type error. I would rather explicitly request an array of keys and then map over that. Anyone else feel the same way or is it just me? |
@brianmaissy we could rely on arity but it's not backwards compatible. JavaScript functions do not have to define all arguments and you can call them with fewer arguments than they were defined with too. For example, fs.readFile can take two or three arguments depending on whether you specify encoding. In our case we'd risk passing the index or key as the encoding in a case like this, meaning we'd always have to wrap the function instead of using it directly. Thankfully, it's actual definition is |
@brianmaissy I also agree with your suggested order of arguments: Edit: I could actually go either way on this since I assume the proposed API is based on the JavaScript forEach method which passes: value, index, array |
@caolan Ah ok now I see the issue. That is messy. I think passing the key and value all the time is clearer anyway. @dominicbarnes Are you still working on this? |
I was just about to sit down and work on this, which direction should I go ahead and go? Sounds like the consensus is to overload async.forEach and friends, and possibly also implementing passing the index/key for both arrays and objects. Since my original PR here took the alternate approach, perhaps I should create a new branch, and a new PR for the discussion to continue there? |
@dominicbarnes changing the arity of iterators for forEach etc. would be a real pain now. I think your original suggestion was good, let's implement new functions such as forEachOf since variable arity could also get confusing. |
@dominicbarnes and if forEachOf could support arrays too then it deals with people asking for the index to be passed to iterators as well :) |
Roger that @caolan, I'll try and finish fleshing out these changes before the end of this coming weekend. :) |
Alright, so far I've implemented: forEachOf, forEachOfSeries, forEachOfLimit @caolan Would you review what I have so far? Also, should I continue and implement the same behavior for map, filter, reject, etc? (I'm guessing not in order to keep this PR as simple as possible, adding all of those variants will make this a pretty hefty PR) |
Oops, seems I have been working on the same thing. #321. I did not implement it as a different function though, I simply check the function arity.
IMO, it would be worth breaking backwards compatibility for the sake of elegance and following the Javascript forEach convention. Would it be such a big deal if this was part of a major release? In addition, I doubt that so many people use async.forEach with 3 arguments functions anyways. |
You're right, we could change it at a major release. But how and when that happens is caolan's call |
Any update on this? |
@caolan what is status of this? |
+1 This would be really helpful. What's the status? |
+1 I've just started investigating this library and this particular issue is a showstopper. Shame. I'm trying to load a paginated list of items from a redis database and need to asynchronously load the items but preserve order. .eachSeries will have the performance of a blocking IO and all I need is the key/index in the .each (or equivalent). |
Workaround: async.each(Object.keys(res), function (key, cb) {
var val = res[key];
console.log(val);
cb();
}, cb); PS: Won't iterate properties on prototype. |
I realise this is now ancient history, but if someone wants to add docs and make sure the tests still pass I'll merge this. I don't like overloading the each/eachSeries to handle keys or indexes so this seems like the best approach. Personally, I just iterate over Object.keys(). |
forIn? like in lodash |
+1 How is this feature progressing? I would keep the js convention "iterator(key, value, callback)" and always pass the three arguments along. It makes sense to me to change the current implementation of the "each" family, without creating duplicates, although I understand it could break old code. This would happen only if someone updates the library though, and it could be made clear in the docs that it's a major realease with potentially breaking changes. |
+1, I might be able to help document and test this sometime this week. |
I know there is a workaround, and I know this is free software etc., but I humbly vote +1 for this to be merged... |
+1 |
Well, last year @caolan wrote:
So, I am pretty sure he won't say "no" to a pull request that doesn't overload |
Waiting on #705, which complete this.... |
you guys need to change the docs, please, there is still a reference to async.forEachOf in the readme.md file |
@the1mills what do you mean? |
i am on version "version": "0.9.2", |
0.9.2 does not have |
Yup, and forEachOf is in the docs or at least the readme.md file that shows up in this repo |
is there a newer version thant 0.9.2... |
Yes, latest is 1.4.2. The docs for 0.9.2 can be found here: https://github.com/caolan/async/tree/0.9.2 |
whoops thx |
So, I needed the ability to iterate objects (and get the
key
passed into the iterator) and noticed it was not done because it would break compatibility with the Node.js standard libs. I am proposing this "convention" of adding theOf
suffix on iterators that deal with objects. (instead of arrays)If this entire concept is rejected outright, then I'll stop here. However, if this seems like a good idea/convention I can finish up adding the same concept to the other various collection iterators.
Usage: