4
\$\begingroup\$

I'm trying to get an object with ratings and titles properties:

{
  ratings: [3, 5],
  titles: ['Movie1', 'Movie2']
}

from the following two functions:

const getMovies = () => {
  return new Promise((resolve) => {
    resolve([
      {
        movieId: 1,
        rating: 3
      },
      {
        movieId: 2,
        rating: 5
      }
    ]);
  });
};
const getTitle = (movieId) => {
  return new Promise((resolve, reject) => {
    switch (movieId) {
      case 1:
        resolve({ title: "Movie1" });
        break;
      case 2:
        resolve({ title: "Movie2" });
        break;
      default:
        reject(new Error("404 - movie not found"));
    }
  });
};

I'm avoiding async/await, so trying to get that result using then.

Here is my approach:

const result = {}

getMovies()
  .then((movies) => {
    result.ratings = movies.map(({rating}) => rating)
    return Promise.all(movies.map(({ movieId }) => getTitle(movieId)));
  })
  .then((titles) => {
    result.titles = titles.map(({title}) => title)
    console.log(result)
  })
  .catch(console.log)

Can I do this in a better way withou having to nest then inside then? I don't like the use of a external variable to gather my result, but I don't like the nested thens in this other approach:

getMovies()
  .then((movies) => {
    Promise.all(movies.map(({ movieId }) => getTitle(movieId)))
      .then((titles) => {
        console.log({
          ratings: movies.map(({rating}) => rating),
          titles: titles.map(({title}) => title),
        })
      })
      .catch(console.log)
  })
  .catch(console.log)

How can I improve this using then and not async/await?

\$\endgroup\$
  • \$\begingroup\$ About getMovies: what is returned? An object like this: {movieId:..., title:..., rating:...}? If you code it, how do you decide those values? I'm confused... And the object you are trying to get, why not: movies={movieId001:{title:"some title", rating:some rating}, movieId002:{title........},...}? \$\endgroup\$ – iAmOren Sep 28 at 22:43
  • 1
    \$\begingroup\$ I'm also curious about the avoidance of async/await for the inner Promise.all for the titles, or just in general. What is the reason for not wanting to use async/await? \$\endgroup\$ – Drew Reese Sep 28 at 22:50
  • \$\begingroup\$ This is just a contrived example; I'm doing this as an exercise to get a better understanding of the use of then with promises. \$\endgroup\$ – MauricioRobayo Sep 28 at 23:59
  • \$\begingroup\$ Promises exist so you can deal with asynchronous code. You will hardly get any understanding of them if you only try to use it with synchronous code. Writing synchronous code with promises is probably only useful for stubs - to fullfill an interface. Otherwise it Is just unnecesary burden and any sane reviewer will first of all tell you to not use promises for synchronous code. \$\endgroup\$ – slepic Sep 29 at 3:16
  • 1
    \$\begingroup\$ @slepic I never said I'm doing this to get a better understanding of promises, I said I'm doing this to get a better understanding of the use of then. Anyway, thanks for your input. \$\endgroup\$ – MauricioRobayo Sep 29 at 11:49
5
\$\begingroup\$

You could do like so if you prefer, essentially just pass forward the data i the promises. You could write your own promiseAllObject if you want it to be slightly neater.

const result = getMovies()
  .then(movies => {
    return Promise.all([
      Promise.all(movies.map(({ movieId }) => getTitle(movieId))),
      movies.map(_ => _.rating)
    ]);
  })
  .then(([titlesObj, ratings]) => ({
    titles: titlesObj.map(_ => _.title),
    ratings
  }))
  .catch(console.log);

result.then(r => console.log(r));
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Nice! Thanks, this is really helpful, I appreciate a lot you took the time to provide this feedback. \$\endgroup\$ – MauricioRobayo Sep 29 at 0:03
1
\$\begingroup\$

The premise of your question indicates that you've identified one of the flaws of promises.

Asynchronous code like this should return an observable which you can then choose to convert to a promise. When it's an observable you can use the full range of operators available in RxJs, make the changes you need in that pipeline, and then finish off with a toPromise().

Apologies, but I don't have an environment available to put together an example and reactive programming is challenging even with an IDE. I would simply recommend you learn about observables and reactive programming. Once you understand that, promises become trivial.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.