1

I want to create one Promise that, internally, calls a series of asynchronous methods in sequence and returns the results of these methods, concatenated in an ordered Array, once the last method returns.

I was trying this:

const getArray = function (thisArray) {
    return new Promise ( function (resolve, reject) {
        if (thisArray.length < 3) {
            setTimeout(function() {
                console.log('adding element');
                thisArray.push(thisArray.length);
                getArray(thisArray);
            },  1000); 
        } else {
            console.log(thisArray);
            console.log('resolving');
            resolve(thisArray);
        }
    });
}

getArray([]).then(function(data) {
    console.log('thened');
    console.log(data);
})

but it doesn't ever calls the then(). How can I do this?

trincot
  • 317,000
  • 35
  • 244
  • 286
Jose Ospina
  • 2,097
  • 3
  • 26
  • 40
  • Some of the answers to [*How to return the response from an asynchronous call?*](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) address resolving a series of promises like that (and parallel ones too). – T.J. Crowder Oct 31 '17 at 15:43
  • It's not clear to me how the code there relates to your description of what you're trying to do. – T.J. Crowder Oct 31 '17 at 15:44
  • @T.J.Crowder, you can run it. It uses recursion to guarantee sequence, and builds the array just before sending it to the resolve( . ) call, so I thought I was close to getting it to work. Perhaps not. Perhaps the whole structure is wrong. – Jose Ospina Oct 31 '17 at 15:47
  • 1
    I have updated it. – Jose Ospina Oct 31 '17 at 15:51
  • In your real scenario, don't you have existing information you're looping over? Rather than just creating things from scratch? – T.J. Crowder Oct 31 '17 at 15:52

1 Answers1

1

You're not far off at all, you just need to be sure to call resolve for each new Promise. If you're still building the array, you pass the resulting promise from your recursive getArray call; otherwise, you pass the array:

const getArray = function(thisArray) {
    return new Promise((resolve, reject) => {
        if (thisArray.length >= 3) {
            // All done
            resolve(thisArray);
        } else {
            // Do something async...
            setTimeout(() => {
                // ...add the result
                console.log('adding element');
                thisArray.push(thisArray.length);
                // ...and recurse
                resolve(getArray(thisArray));
            }, 1000);
        }
    });
}

getArray([]).then(data => {
    console.log('done');
    console.log(data);
});

That's a bit cleaner if you separate the function doing the async work from getArray, and ensure that the function doing the async work returns a promise. For our purposes, we can just wrap setTimeout in a Promise wrapper:

const setTimeoutP = (cb, delay) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(cb());
        }, delay);
    });
};

then:

const getArray = thisArray => {
    if (thisArray.length >= 3) {
        return Promise.resolve(thisArray);
    }
    return setTimeoutP(() => {
        console.log("adding element");
        thisArray.push(thisArray.length);
    });
};

Live copy:

const setTimeoutP = (cb, delay) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(cb());
        }, delay);
    });
};

const getArray = thisArray => {
    if (thisArray.length >= 3) {
        return Promise.resolve(thisArray);
    }
    return setTimeoutP(() => {
        console.log("adding element");
        thisArray.push(thisArray.length);
        return getArray(thisArray);
    }, 1000);
};

getArray([]).then(data => {
    console.log('done');
    console.log(data);
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875