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\$
5
  • \$\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, 2020 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, 2020 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\$ Sep 28, 2020 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, 2020 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\$ Sep 29, 2020 at 11:49

2 Answers 2

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));
\$\endgroup\$
1
  • \$\begingroup\$ Nice! Thanks, this is really helpful, I appreciate a lot you took the time to provide this feedback. \$\endgroup\$ Sep 29, 2020 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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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