0

I want to proceed when all promises are either resolved or rejected and display the string "##### should be final call ####" at the end.


TL;DR;

I forgot to return the promise in the map function.


I am trying to use this approach: Wait until all ES6 promises complete, even rejected promises

What is the problem with the below code?

I would expect the .then handler of Promise.all() to be called at last, after all others.

The result variable contains an array with undefined values.

console.clear();

$(document).ready(function () {

    var url = "https://httpbin.org/get?";
    a = [];

    a.push(new Promise(function (resolve, reject) {
        $.get(url + Math.random()).then((res) => resolve()).fail(() => {
            reject();
        });
    }));
    a.push(new Promise(function (resolve, reject) {
        $.get(url + Math.random()).then((res) => resolve()).fail(() => {
            reject();
        });
    }));

    var mr = getPromise();

    function getPromise() {
        var promise = new Promise(function (resolve, reject) {
            window.setTimeout(function () {
                reject();

            }, 1000);
        });
        return promise;
    }

    a.push(mr);

    a.push(new Promise(function (resolve, reject) {
        $.get(url + Math.random()).then((res) => resolve()).fail(() => {
            reject();
        });
    }));

    a.push(new Promise(function (resolve, reject) {
        $.get(url + Math.random()).then((res) => resolve()).fail(() => {
            reject();
        });
    }));

    Promise.all(a.map((p) => {
            p.catch((e) => {
                console.log("failed promise catch");
            });
        }))
        .then((results) => {
            console.log("##### should be  final call  ####");
        })
        .catch((e) => {
            console.log("final catch block executed");
        });


}); // ready end
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Legends
  • 21,202
  • 16
  • 97
  • 123

2 Answers2

2

First of all, avoid the Promise constructor antipattern! Simply use

function getPromise() {
  return new Promise(function(resolve, reject) {
    window.setTimeout(reject, 1000);
  });
}
const url = "https://httpbin.org/get?";
a = [
  Promise.resolve($.get(url+ Math.random())),
  Promise.resolve($.get(url+ Math.random())),
  getPromise(),
  Promise.resolve($.get(url+ Math.random())),
  Promise.resolve($.get(url+ Math.random()))
];

Then your problem is just that you forgot to return the chained promise (with the handled rejections) from the map callback, so you had called Promise.all on an array of undefineds which immediately fulfilled. Change it to:

Promise.all(a.map(p => {
  return p.catch(e => { console.log("failed promise catch"); });
//^^^^^^
}))
.then(results => {
  console.log("##### should be  final call  ####");
}, e => {
  console.log("final catch block executed");
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks Bergi. But I have one further question regarding `Promise.resolve(..)`. What if the `.then` handler of the `$.get` request relies on data from the currently executing function context. In `Promise.then(..)` I only get the result of the request... – Legends Jan 28 '18 at 19:41
  • And [here](https://stackoverflow.com/a/30008115/2581562) a highly upvoted answer, which uses this anti pattern to promisify native xhr requests. Actually all the answers use this anti pattern. – Legends Jan 28 '18 at 19:56
  • @Legends What do you mean by "currently executing context"? There's nothing that couldn't be done with `then` as well. – Bergi Jan 28 '18 at 22:00
  • 1
    @Legends No, it's not an antipattern to use the `Promise` constructor for promisifying anything. It is an antipattern to try to promisify a thing that already returns a promise (like `$.ajax` or `fetch`), or to write your own (but worse) `then` pattern. – Bergi Jan 28 '18 at 22:01
  • Here is also the answer to my first question in this comment thread regarding additional context parameters when using `Promise.resolve` [https://stackoverflow.com/a/22776850/2581562](https://stackoverflow.com/a/22776850/2581562) – Legends Jan 28 '18 at 22:10
1

You forgot to return promise into map. You promised array of undefined which is resolved immediately.

console.clear();

$(document).ready(function(){

function getPromise() {
  return new Promise((resolve, reject) => window.setTimeout(reject, 1000));
}

function getRandomUrl() {
  return new Promise((resolve, reject) => $.get(url+ Math.random()).done(resolve).fail(reject));
}

var url= "https://httpbin.org/get?";
a = [];

a.push(getRandomUrl());
a.push(getRandomUrl());
a.push(getPromise());
a.push(getRandomUrl());
a.push(getRandomUrl());

Promise.all(a.map(p => {
    return p.catch(console.log);   
  }))
  .then((results) => {
    console.log("##### should be  final call  ####");
  })
  .catch((e) => {
    console.log("final catch block executed");
  });


});// ready end
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
bigless
  • 2,849
  • 19
  • 31