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;
}
CodePudding user response:
Some comments:
Yes, you can use
Promise.all
. There is no issue with the order, asPromise.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 anarray
parameter, as it has all it needs to create the array itself and then return it.Instead of
.forEach
andpush
, use.map
andreturn
.res.data.results.books
is not a promise, so it is not needed toawait
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.