0

This code essentially gets some data from an api, and puts it in two arrays which I then render on a page using a rendering engine. It works, but I am wondering if there is a different approach to this that is better (because the first await call will have to complete before the second one does - maybe with Promise.all - but then how do I pass the arrays in to render? Most of the code examples I've seen directly return from Promise.all [return await Promise.all(etc)])

app.get('/', async (req, res) => {
    const fic = [];
    const non = [];
    await getBooks(fic, API.URL_HARDCOVER_FICTION);
    await getBooks(non, API.URL_HARDCOVER_NONFICTION);
    res.render('layout', {results: {fic: fic, non: non}});
});

const getBooks = async (array, url)  => {
    await axios.get(url + "?api-key=" + API.Key)
        .then( async res => {
          const list = await res.data.results.books;
          list.forEach( book => {
            array.push(new Book(
              book.primary_isbn13,
              book.title,
              book.author));
          })
        })
        .catch(error => {
          console.error(error);
        });
    return array;
}
1
  • If you change the signature of the getBooks method not to take an array as first param, but simply return one, you can then do: const [fic, non] = await Promise.all([getBooks(API.URL...), getBooks(API.URL...)]) and keep your render call as-is Commented Sep 5, 2022 at 19:37

1 Answer 1

1

Some comments:

  • Yes, you can use Promise.all. There is no issue with the order, as Promise.all will resolve to an array of fulfilment values that come in the same order as the array of promises you pass as argument.

  • getBooks should not need an array parameter, as it has all it needs to create the array itself and then return it.

  • Instead of .forEach and push, use .map and return.

  • res.data.results.books is not a promise, so it is not needed to await that expression.

Adapted code:

app.get('/', async (req, res) => {
    const urls = [API.URL_HARDCOVER_FICTION, API.URL_HARDCOVER_NONFICTION];
    const [fic, non] = await Promise.all(urls.map(getBooks));
    res.render('layout', {results: {fic, non}});
});

const getBooks = async (url) => {
    const res = await axios.get(url + "?api-key=" + API.Key);
    return res.data.results.books.map(book => new Book(
        book.primary_isbn13,
        book.title,
        book.author
    ));
};

I left out the error handling. First make sure this works and then add a try..catch block.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.