medikoo / deferred

Modular and fast Promises implementation for JavaScript
ISC License
364 stars 20 forks source link

Objects as collections - map, some etc. #9

Closed xixixao closed 11 years ago

xixixao commented 11 years ago

What is the best practice for emulating map, some etc. on object values and keys instead of arrays? Possible addition?

While I am asking, it would be nice to provide or point to an explanation of differences (advantages) of deferred over Q.

medikoo commented 11 years ago

@xixixao Concerning map for objects It depends on use case. Can you describe yours?

When I deal with async operations which for some reason I collect in a key/value map I usually don't need to get a result hash with all values resolved, instead I keep it as hash of promises, and work with it that way.

So plain speaking there's no map for objects as there was no real use case yet to have it.

Concerning deferred over Q comparison. Firstly I don't want to bash Q to much, work of Kris Kowal, was real inspiration for this library, and through his work, I get to really know the concept of promises. Anyway Q in my eyes a bit over theorized and at the time it didn't solve my practical needs. Putting points generally, it would be:

  1. Big performance difference, Q for various reasons is magnitudes slower and introduces asynchronicity on it's own which makes things slower further. I work with scripts that at some times handle hundreds of async operations at one time, Q would be no go for that. I shown that difference in benchmarks included in the repository.
  2. Deferred in my eyes provides simpler and more composable API. Technically anything you rewrite from Q to deferred will look cleaner and simpler, good example of that opens main documentation.
  3. Many core functionalities like deferred.promisify or promise.done (previously named promise.end) appeared in Q much later. Without promise.done there's no way to expose unhandled exceptions which otherwise remain silent, and promisify is crucial to integrate with Node.js callbacks style. Still even Q's counterpart for promisify leaves a lot to desire, it started with two not really composable solutions, now I think they're trying to fix that.
  4. Deferred's codebase is modular, well tested and I believe much more solid. Currently there's no single bug in deferred that I'm aware of, and I use it in really intense stuff.

I'm gonna close this issue for now, but we can keep discussion here (see also deferred group on google).

If you really feel there needs to be some map counterpart for objects, please explain with valid use case, and reopen. We'll see what's best solution for that.

xixixao commented 11 years ago

Thank you for the comparison, very much appreciated.

For the use case (using Q because I came across it first):

db = mongoose.connection
Q.map db.collections, (collection) ->
  Q.ninvoke collection, 'drop'

Where Q.map is actually my implementation, like deferred.map (again, before I found out about deferred):

Q.map = (values, callback) ->
  if Array.isArray values
    Q.all values.map callback
  else
    Q.all (callback v, k for k, v of values)

Also libraries such as underscore provided iteration for both objects and arrays.

medikoo commented 11 years ago

@xixixao thanks, and in that case db.collections is an array, so you can use deferred.map without issues.

Have you approached the case where you wanted to use your Q.map on hash object?

xixixao commented 11 years ago

No no, in that case db.collections is a map from name of collections to their objects.

medikoo commented 11 years ago

@xixixao ah indeed. I thought they match native driver api.

In such case, I would fallback to lang utitlity of your choice (e.g. underscore) and do:

Collection.prototype.pdrop = deferred.promisify(Collection.prototype.drop);

deferred.map(values(db.collections), function (collection) { return collection.pdrop(); });