1

I am trying to collect data asynchronously using jQuery and Promise. Here's a brief idea of my code:

(function () {
    let promises = [], results = [];
    const urls = ["https://cdn.jsdelivr.net/gh/rails/rails/MIT-LICENSE"];
    for (let url of urls) {
        let p = $.get(url).then(
            // The actual job is to parse the response and make new requests
            // but for simplicity I'll just make the same request again here
            () => promises.push(
                $.get(url).then(
                    data => results.push(data))));
        promises.push(p);
    }
    console.log("Start");
    Promise.all(promises).then(function () {
        console.log("Done");
        console.log(results);
    });
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

The strange thing is, I can see a noticeable delay before the console.log runs, but an empty array appears in my console. However, if I immediately enter results, I can see everything expected there. I see no error, either.

I believe it has something to do with me nesting promises in promises, but I have no idea how to hunt the bug down.

iBug
  • 35,554
  • 7
  • 89
  • 134
  • 2
    Mmh, it looks like it should work, but there is no reason to do it in such a strange way. Just do `promises.push($.get(url))` and `Promise.all(promises).then(function (results) { console.log(results); });` – Felix Kling Jan 08 '20 at 16:28
  • @Pointy It's probably not that way in the real code, or there would be console errors. – Barmar Jan 08 '20 at 16:28
  • Can you post the actual code instead of a "brief idea"? The problem may be in something you left out because you didn't think it was important. – Barmar Jan 08 '20 at 16:29
  • Sorry all, I realized that this is not reproducing the error. I'm working on another MCVE. – iBug Jan 08 '20 at 16:31
  • Now the code is making *two* HTTP requests. I think you might make more progress if you'd trace what's going on (`console.log()`) yourself. – Pointy Jan 08 '20 at 16:41
  • @Pointy But the second (inner) promise is inserted correctly into `promises`, right? – iBug Jan 08 '20 at 16:42
  • `.then(results.push)` should be `.then(results.push.bind(results))` – Barmar Jan 08 '20 at 16:44
  • Well surely you don't really want to make each HTTP request twice, right? – Pointy Jan 08 '20 at 16:45
  • @Barmar I'm using `results.push` as a shorthand for `data => results.push(data)`. – iBug Jan 08 '20 at 16:45
  • @Pointy Making two requests isn't the point here, nesting asynchronous requests (nesting Promises) is. – iBug Jan 08 '20 at 16:46
  • When you call `Promise.all()` at the end, the `promises` array only contains the outer promises, not the inner promises, because they're added asynchronously. – Barmar Jan 08 '20 at 16:46
  • @iBug I know what you're trying to do with that, but it doesn't work as you've written it. – Barmar Jan 08 '20 at 16:46
  • Have a look at [this](https://stackoverflow.com/a/45704116/1048572) or [that](https://stackoverflow.com/q/37801654/1048572) – Bergi Jan 08 '20 at 18:10

1 Answers1

1

This is how promises are handled using Promise.all. Push the promise into an array. Than resolve that array of promises, which will give the array of values.

var promises = [];
for (let url of urls) {
    // Save promise in p
    let p = $.get(url)
    // push promise p in promises array
    promises.push(p);
}
// resolve all promises
Promise.all(promises).then(function (results) {
    console.log(results);
});

The original code does not work because for each url, the value stored in p is a promise that will resolve to undefined as then is not returning anything.

(function () {
let promises = [], results = [];
const urls = ["https://cdn.jsdelivr.net/gh/rails/rails/MIT-LICENSE"];
for (let url of urls) {
    let p = $.get(url).then(d => {
    results.push(d);
    // return the value
    return d;
    });
    promises.push(p);
}
console.log("Start");
console.log(promises);
Promise.all(promises).then(function () {
    console.log("Done");
    console.log(results);
});
})();

This will work.

Satvik Daga
  • 156
  • 4