8

I need to download a collection of images on button press. Currently, I'm doing it this way using react-native-fs:

const downloadImageItem = async (imgUrl, id) => {
  const path = `${RNFS.DocumentDirectoryPath}/${id}.jpg`;

  RNFS.downloadFile({
    fromUrl: imgUrl,
    toFile: path,
  });
};
const downloadImages = async (items) => {
  for (const item of items) {
    if (item.images.length) {
      await downloadImageItem(item.images[0].thumb, item.images[0].id);
    }
  }
  return Promise.resolve();
};

Calling the function from my reducer for 3 types of items:

await downloadImages(items_one);
await downloadImages(items_two);
await downloadImages(items_three);

My issue is that sometimes I receive an error message that says: Excessive number of pending callbacks: 501

Is there a better way of doing the same thing, so that the error does not appear?

Oleksandr Fomin
  • 2,005
  • 5
  • 25
  • 47

3 Answers3

9

A similar issue was opened on the react-native repository in December 2019, it still hasn't been closed or addressed but I think you may find this comment useful.

The problem being described there is that queueing too many Promise calls can be problematic. The commenter suggested using a Promise utility function called Promise.map() which has concurrency control out of the box, from the bluebird library.

emeraldsanto
  • 4,330
  • 1
  • 12
  • 25
  • I'm not sure what I'm doing wrong here but I keep getting ```TypeError: Promise.map is not a function``` error message. Even though I made an import ```import * as Promise from 'bluebird'```. And refactored the download function as follows: ```const downloadImages = async (items) => { await Promise.map(items, (item) => downloadImageItem(item), { concurrency: 200, }); return Promise.resolve(); }``` – Oleksandr Fomin Apr 28 '20 at 14:46
  • Did you install the package correctly? Either npm or yarn. Here's the [docs](http://bluebirdjs.com/docs/api/promise.map.html) for the `Promise.map()` function. – emeraldsanto Apr 28 '20 at 17:00
  • Trying to use it, but can't make it work. If you can, please take a look at: https://github.com/petkaantonov/bluebird/issues/1652 – Yossi Jul 14 '20 at 17:29
1

Instead of using await inside for, try using for await

for await (variable of iterable) {
  sentence
}
const downloadImages = async (items) => {
  for await(const item of items) {
    if (item.images.length) {
      downloadImageItem(item.images[0].thumb, item.images[0].id);
    }
  }
  return Promise.resolve();
};
0

I had the same issue; to me, it was because of a long chain of promises I had inside a component.

Once I moved the function to a different file the warning disappeared.