Search code examples
javascriptjquerypromisees6-promise

Continue after array of promises has completed either with success or fail


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>


Solution

  • 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");
    });