2

I am building a script that retrieves data from an API to build my own database. I'm rate limited to a relatively low number calls per hour.

I must make several sequential calls to different databases to gather the data I need, and this must be done in sequentially, because I don't know what to call from the next database until I receive the value from the first database.

I need to run these sequential fetches for each item in an array, that I need to gather additional data for.

I have written this script as a boilerplate, but I feel like it's not as simple, or as best practice as it should be, and I'm looking for critique.

The setTimeout is incorporated to slow down the fetches so I don't exceed the rate limit and get blocked. Using chained promises in a reduce function seemed to be the best way... But that's what I'm not sure about. Is there a simpler way to accomplish this?

    let myArray = ["beans", "soup", "peanuts", "artichokes"];

    myArray.reduce((promise, item) => {
        return promise.then(() => {
            return itemsPromise(item);
        });
    }, Promise.resolve()).then(() => {
        console.log("ALL DONE");
    })

    let itemsPromise = (item) => {
        console.log("Item: ", item);
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve();
            }, 2000);
        });
    }

This script successfully logs the item to the console with the expected 2 second delay. In real life, I'll be running an api call instead of logging to console.

Matthew Rideout
  • 7,330
  • 2
  • 42
  • 61
  • 2
    Using `.reduce()` with promises like you are is one design pattern for serializing asynchronous calls and wrapping a promise around `setTimeout()` is how you insert a delay in a promise chain. The Bluebird promise library has sequencing operations and delay operations built-in if you wanted to use some pre-built tools rather than this, but there's nothing wrong with what you have. – jfriend00 Mar 17 '18 at 18:45
  • An example of `.reduce()` with a delay in this answer: [How to synchronize a sequence of promises](https://stackoverflow.com/questions/29880715/how-to-synchronize-a-sequence-of-promises/29906506#29906506). Could also use `for` loop and `async/await`. – jfriend00 Mar 17 '18 at 19:21

1 Answers1

0

I almost like the promise sequencing pattern by .reduce() but i also feel like that initial dummy promise is kind of hairy. So by putting spread and rest operator at work you may instead do something in a Haskellesque recursive fashion as follows;

var myArray     = ["beans", "soup", "peanuts", "artichokes"],
    doSomething = console.log,
    seqItems    = (i,...is) => is.length ? itemPromise(i).then(v => (doSomething(v), seqItems(...is)))
                                         : itemPromise(i).then(doSomething),
    itemPromise = item => new Promise((resolve, reject) => setTimeout(resolve, 2000, item));

seqItems(...myArray);
Redu
  • 25,060
  • 6
  • 56
  • 76