Nesting Promises

If the result handler for a Promise resolves with another Promise, the .then() method of the original Promise will be called with resolved value of the nested one:

const myPromise = new Promise((resolve) => resolve(Promise.resolve(7)))
myPromise.then(console.log)
// will print "7"

Another example would be fetching all items from an API that allows to query only a limited number of items per request and we don't know beforehand how many items are there for us to fetch.
We can achieve this by writing a function that queries for the allowed number of items. If the number of items in the response equals the limit, we fetch the next batch of items and continue to do so until the results are fewer than the limit. In this case we can resolve with the list of all items we received in our previous calls.

When invoking this function, we don't have to care about how often it had to recurse and call itself. We just receive the complete list of items:

const fetchAllItems = (queryParams = {start: 0, max: 100}, allItems = []) =>
// fetch also returns a Promise, no need to wrap it with `new Promise()`
fetch('/api/items?' + new URLSearchParams(queryParams).toString())
.then(response => response.json())
.then((items) => {
// add the items we received this to the items we received before
allItems.push.apply(allItems, items)

if(items.length === queryParams.max) {
// if the number of items we received is equal to the limit,
// return with another call to the function
return fetchAllItems({
...queryParams,
start: queryParams.start + queryParams.max
}, allItems)
} else {
// otherwise return the list of collected items
return allItems
}
})


fetchAllItems()
.then(allItems => {
console.log(allItems)
// do something useful
})
.catch(error => console.error('Something went wrong:', error.message))
Published: December 17th, 2020
Tags: til,JS