3

I've been playing with promises, and usually can figure out how to handle them well, but in this situation, I can't figure out how to remove one promise-wrapping level.

Here is the code:

let promise2 = promise1.then((nodes) => {
  return Promise.all(nodes.map(n => {

    // findConnections returns a promise
    return this.findConnections(n.get("spotifyData")); 
  }));
});

Now I would expect promise2 to wrap an array, but it doesn't, it wraps a promise wrapping an array. If I want to access the array, I have to do this:

promise2.then(level1 => level1.then(level2 => console.log(level2)));

level1 is a promise itself.

Of course, I could work with that, but I find the code very ugly, and I'd like to simplify it so that you can do:

promise2.then(level1 => console.log(level1))

and directly get an array there.

Any ideas ?

Thanks!

EDIT:

The findConnections() method:

findConnections: function (node) {
  return Ember.$.get("https://api.spotify.com/v1/artists/" + node.id + "/related-artists").then((data) => {
     return data.artists;
  });
}
Thomas P
  • 33
  • 4
  • *level1 is a promise itself.* - No, it would be an array of values. Check the example [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all#Examples) – thefourtheye Jul 16 '15 at 17:02
  • Then why can't I access its content without using .then() ? – Thomas P Jul 16 '15 at 17:06
  • Check this [online demo](https://babeljs.io/repl/#?experimental=true&evaluate=true&loose=false&spec=false&code=const%20promise1%20%3D%20Promise.resolve(%5B1%2C%202%2C%203%5D)%3B%0A%0Aconst%20promise2%20%3D%20promise1.then(function(nodes)%20%7B%0A%20%20%20%20return%20Promise.all(nodes.map(function(currentNode)%20%7B%0A%20%20%20%20%20%20%20%20return%20Promise.resolve(currentNode%20*%202)%3B%0A%20%20%20%20%7D))%3B%0A%7D)%3B%0A%0Apromise2.then(console.log.bind(console))%3B%0A) – thefourtheye Jul 16 '15 at 17:16
  • Ok, then there is some other problem that I can't diagnose, because in my case, the last call to `promise2.then(console.log.bind(console));` logs Promise. Any idea why ? – Thomas P Jul 16 '15 at 17:30
  • Try adding `console.log('processing');` right after the `promise2.then(console.log.bind(console));` line. I think you might be confusing the RE**P**L's output with the output from `console`. – idbehold Jul 16 '15 at 17:44
  • I'm in a browser, I don't have a REPL, but tried anyways, I get "processing", and then the Promise being logged. – Thomas P Jul 16 '15 at 17:47
  • The devtools js console you're running the code in is a REPL. Are you using native Promises or some library? – idbehold Jul 16 '15 at 17:49
  • I tried both with native promises and Ember's implementation (which is supposed to be compatible with the spec), no luck. – Thomas P Jul 16 '15 at 17:51
  • Assuming `n.get("spotifyData")` is synchronous, can you possibly show us your code for the `this.findConnections()` method? – idbehold Jul 16 '15 at 17:55
  • `n.get()` is the Ember get method, and this is synchronous. Code added for findConnections() – Thomas P Jul 16 '15 at 17:56
  • Which implementation are you using, what is `Promise`, and where does `promise1` come from? – Bergi Jul 16 '15 at 18:44

1 Answers1

1

level1 is a promise itself.

No it's not. Ember does use RSVP, which is Promises/A+ compatible, and that means that then callbacks are never called with a promise (or thenable). They always receive a plain value.

Promises/A+ does mandate that there are no nested promises returned from then. They are always recursively unwrapped. You can just do

promise2.then(connections => console.log(connections));

If this really doesn't work, that would suggest that promise1 is no real (or at least no standard-conformant) promise, and you should do promise1 = Promise.resolve(promise1) first.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • You are absolutely right about adding `promise1 = Promise.resolve(promise1)` first. It's very strange, though, because promise1 is the result of a call to `Ember.$.get()` Is jQuery get not supposed to return a standard compliant promise ? – Thomas P Jul 16 '15 at 18:55
  • @ThomasP: jQuery? Muahahaha. Um, [no, unfortunately not](http://stackoverflow.com/a/31327725/1048572), jQuery `then` does only work with jQuery's own promises. – Bergi Jul 16 '15 at 18:58
  • So it would have worked if you had wrapped the `Promise.all()` call in a `$.when(…)` :-) – Bergi Jul 16 '15 at 19:12
  • 1
    Yeah, but it looks like it also works if I only wrap the original $.get() with Ember.RSVP.Promise.resolve(), which gives me a standard compliant promise, and the easy AJAX of jQuery. Pretty sad that jQuery isn't compliant, but good enough. Thanks a lot for your time! – Thomas P Jul 16 '15 at 20:08