Search code examples
javascriptnode.jsreactjsasynchronouses6-promise

Cancelling nested Promise.all when one rejects


I have a react component which deals with downloading a list of articles to localStorage.

Each article has an endpoint which I can hit to get an array of image links, which I also need to save.

const getImageLinkPromise = link => {
    return Api.fetch(link)
    .then(image => {
        if (!this.mounted) {
            return Promise.reject();
        }
        return image;
     });
}

const getArticlePromise = article => {
    return Api.fetch(article.imageCollectionId)
    .then(imageLinks => imageLinks.map(getImageLinkPromise)
    .then(linkPromises => Promise.all(linkPromises))
    .then(images => //fetch some more data for the article)
}

const articlePromises = articleData.map(getArticlePromise);

Promise.all(articlePromises).then(completeArticles => // do stuff);

here is some rough code which shows what i mean

The problem is, when a user navigates away from the page and the component is unmounted, I want to halt any currently running promises. I did this by adding a check for isMounted in the getImageLinkPromise and then return Promise.reject() if so.

Even though I reject the promise, the rest of the promises still run for all of the images in all of the articles.

How can I stop the nested image promises from running if one of them fails the isMounted check?

(if I check isMounted before fetching the they all return true immediately)


Solution

  • .fetch() returns Promise, not the XHR object. Promise is read-only avatar of request, so there is not way to stop request. See How do I cancel an HTTP fetch() request? with bunch of links.

    Since Promise.all() will immediately reject after one of given promises is rejected you should not have any issues with "we are wasting time while awaiting for other requests". I believe the only issue you may have is "upon another promise from list is really resolved it's going forward with saving response in some variable while it is not needed anymore". If so you can just may processing responses in Promise.all(....).then(....). There you'll get list of all the responses only if all have been succeeded.