1

I have some array called photos that is returned in a Promise:

  somePromiseFunc.then (resp) ->
    photos = _.filter resp, 'invalid'
    photos
  .map (photo) ->
    request
      url: photo.url
      method: 'GET'
  .each (photo_contents) ->
    # HERE I NEED THE ORIGINAL photo and the photo_contents

How can I get the photo and photo_contents together in the response? Is such a thing possible?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Shamoon
  • 41,293
  • 91
  • 306
  • 570

2 Answers2

3

You could use Promise.all:

somePromiseFunc.then (resp) ->
  photos = _.filter resp, 'invalid'
  photos
.map (photo) ->
  Promise.all [
    photo
    request
      url: photo.url
      method: 'GET'
  ]
.each ([photo, contents]) ->

Since you're using bluebird, you can also use Promise.props if you prefer having the values passed along in an object rather than an array, but all that really does in this particular case is add some extra verbosity:

somePromiseFunc.then (resp) ->
  photos = _.filter resp, 'invalid'
  photos
.map (photo) ->
  Promise.props 
    photo: photo
    contents: request
      url: photo.url
      method: 'GET'
.each ({photo, contents}) ->
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • You could also do `{photo, contents: … }` to lessen the verbosity, though I wonder whether the parentheses (and extra line!) or the duplication are more verbose :-) – Bergi Mar 19 '15 at 20:13
  • @Bergi The second approach uses 13 more non-whitespace characters than the first. Coffeescript users _hate_ non-whitespace characters. ;-) In all seriousness though, adding property names just for the sake of having them feels clunky to me, especially when that nice array destructuring syntax is available. If OP were passing the result of the `map` around somewhere instead of immediately passing into `each`, I would say that the second approach has merit. – JLRishe Mar 19 '15 at 20:24
1

The easiest way would be to combine them in your map callback:

somePromiseFunc().then (resp) ->
  _.filter resp, 'invalid'
.map (photo) ->
  request
    url: photo.url
    method: 'GET'
  .then (photo_content) ->
    [photo, photo_content]
.each ([photo, content]) ->
  # …

Of course you could also use an object instead of an array for the tuple.


An alternative would be to access the previous promise result somehow and then zip the arrays together:

photos = somePromiseFunc().then (resp) ->
  _.filter resp, 'invalid'
contents = photos.map (photo) ->
  request
    url: photo.url
    method: 'GET'
Promise.all [photos, contents]
.then ([photos, contents]) ->
  Promise.each (_.zip photos, contents), ([photo, content]) ->
    # …
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • This nesting of Promises somehow seems... less than desirable – Shamoon Mar 19 '15 at 18:54
  • @Shamoon: You're not really nesting promises, you're nesting them in a loop. See JLRishe's answer for a very similar approach that uses `Promise.all` instead of the inner `.then` (+1 to him) – Bergi Mar 19 '15 at 19:01