1

I have two HTTP calls on a page and they are separate altogether.

vm.$onInit = function() {
    ....
    ....
    //Get all the items only once during initialization
    ds.getAllItems().then(function(result){
      vm.items = result;
     },function(error){
      vm.errorInApi = true;
    });
    .....
    .....
}
vm.getTimes = function(){
    .....
    .....
    HttpWrapper.send(url,{"operation":'GET'}).then(function(times){
                    .....
}

If both the APIs fail then only I need to show a modal.

I can initiate a variable to true and on failure of the APIs, I can make that false and then only show the modal.

But then how long to wait for completion of all the APIs?

guest271314
  • 1
  • 15
  • 104
  • 177
StrugglingCoder
  • 4,781
  • 16
  • 69
  • 103

3 Answers3

1

Hmm... simply invert the polarity of the promises and use Promise.all().

Promise.all() would normally resolve once all promises resolve, so once the promises are inverted, it resolves once all promises get rejected...

var invert = p => new Promise((v, x) => p.then(x, v));

Promise.all([Promise.reject("Error 404"), Promise.reject("Error WTF")].map(invert))
       .then(v => console.log(v));

So as per @guest271314 comment i extend the solution in a silver spoon to show how inverting promises can be applied for this task.

var invert = p => new Promise((v, x) => p.then(x, v)),
    prps   = [Promise.reject("Error 404"), Promise.reject("Error WTF")]; // previously rejected promises

myButton.addEventListener('click', function(e){
                                     setTimeout(function(...p){
                                                  p.push(Promise.reject("Error in Click Event Listener"));
                                                  Promise.all(p.map(invert))
                                                         .then(r => results.textContent = r.reduce((r,nr) => r + " - " + nr));
                                                }, 200, ...prps);
                                   });
<button id="myButton">Check</button>
<p id="results"></p>

If any of the promises including the previously obtained ones or the once in the event handler gets resolved you will get no output.

Redu
  • 25,060
  • 6
  • 56
  • 76
0

You could use Promise.all.

First you should get the two promises in an array. To achieve that, it is probably useful if your two functions return the promise they create:

vm.$onInit = function() {
    ....
    ....
    return ds.getAllItems().then(function(result){
      vm.items = result;
     },function(error){
      vm.errorInApi = true;
    });
}
vm.getTimes = function(){
    .....
    .....
    return HttpWrapper.send(url,{"operation":'GET'}).then(function(times){
                    .....
    });
}

The array would then be built from the return values:

var arr = [];
arr.push(vm.$onInit());
...
arr.push(vm.getTimes());

You write in a comment that getTimes "is called on some button click", so you would do that second push there.

Or, maybe you see another way to get these promises in an array... it does not matter much how you do it, as long as you achieve this.

Then (in that click handler) you need to detect the situation where both the promises are rejected. Promise.all can do that, but you need to flip the promise results:

// Flip promises so that a rejected one is regarded as fulfilled and vice versa:
arr = arr.map(p => p.then(res => { throw res }).catch(err => err));
// Detect that all original promises rejected, i.e. that the new promises all fulfill.
Promise.all(arr).then(function() {
    // execute whatever you need to execute when both ajax calls failed
}).catch(err => err); // ignore
trincot
  • 317,000
  • 35
  • 244
  • 286
  • _"getTimes is called on some button click"_ – guest271314 Aug 10 '17 at 15:02
  • Thanks, @guest271314, I don't think that changes my answer, but I added that quote and a suggestion on where to place the code in that scenario. – trincot Aug 10 '17 at 15:05
  • This will not work if one promise fail the other not execute. Like StanislavKvitash says – Jesus Carrasco Aug 10 '17 at 15:06
  • That wasn't in my update, it was there from the start ;-) – trincot Aug 10 '17 at 15:07
  • I think is better controller with some var and watch, cause if you chain both promises, if one fail the other will not execute, o even first not and second yes. that doesnt mean all was rejected. – Jesus Carrasco Aug 10 '17 at 15:11
  • @JesusCarrasco, what do you mean "will not execute"? The execution is done when `vm.$onInit()` and `vm.getTimes()` are executed, which always happens. Secondly, the promises *are not chained*. – trincot Aug 10 '17 at 15:14
0

You can use async/await and .catch() to determine the number of rejected Promises, perform action if the number is equal to N, where N is the number of rejected Promise values required to perform action.

A prerequisite, as mentioned by @trincot, is to return the Promise from the function and return a value from the function passed to .then(), and throw an Error() from .catch() or function at second parameter of .then() see Why is value undefined at .then() chained to Promise?

const N = 2;

function onInit() {
  return Promise.resolve("resolved")
}

function getTimes() {
  return Promise.reject("rejected");
}

const first = onInit();

document.querySelector("button")
.onclick = async function() {
  let n = 0;
  const firstP = await first.catch(() => ++n);
  const secondP = await getTimes().catch(() => ++n);
  if (n === N) {
    // do stuff if `n` is equal to `N`
  } else {
    // do other stuff
    console.log(n, N)
  }
};
<button>click</button>
guest271314
  • 1
  • 15
  • 104
  • 177