0

I am working with promises. When I chain promises the last then block doesn't get executed. All the other blocks gets executed, but after the last promise resolves nothing happens. Could someone explain to me what I missed?

var x = 1;
$(document).ready(function() {
  getJobId(token).then(function(rsp) {
    return rsp;
  }).then(function(job_id) {
    looper().then(function(rsp) {
      console.log("app finished : " + rsp); // this block never gets called
    });
  });
});

function getJobId(token) {
  // does an API call that returns a promise
  return $.ajax({
    url: "url"
  });
}

function looper() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      // if the call is successful
      if (x == 5) {
        resolve(1); // returns the value 1
      } else {
        x++; // we increment the value of the counter
        console.log("not solved yet");
        looper(); // we call the same function again
      }
    }, 5000); // (waits for 5 seconds)
  });
}
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
iliasse
  • 247
  • 1
  • 7

1 Answers1

2

The problem is that you never resolve the promise you're waiting on, which is the first promise that looper returns.

You must always resolve or reject a promise, or make it depend on another one. In this case, the minimal change to do that would be to make the earlier ones depend on the later one by passing the promise from the subsequent looper into resolve:

resolve(looper()); // we call the same function again

But that's not what I'd do. Instead, I wouldn't have looper call itself. I'd have it handle things directly:

function looper() {
  function loop(resolve, reject) {
    setTimeout(function() {
      // if the call is successful
      if (x == 5) {
        resolve(1); // returns the value 1
      } else {
        x++; // we increment the value of the counter
        console.log("not solved yet");
        loop(resolve, reject);
      }
    }, 5000); // (waits for 5 seconds)
  }
  return new Promise(loop);
}

As a separate issue, you're not handling failures. It's important to do so. In this case, probably return the promise from looper.then in the ready handler and add a catch:

var x = 1;
$(document).ready(function() {
  getJobId(token).then(function(rsp) {
    return rsp;
  }).then(function(job_id) {
    return looper().then(function(rsp) {
      console.log("app finished : " + rsp); // this block never gets called
    });
  }).catch(function(error) {
    // Handle/report error here
  });
});

function getJobId(token) {
  // does an API call that returns a promise
  return $.ajax({
    url: "url"
  });
}

function looper() {
  function loop(resolve, reject) {
    setTimeout(function() {
      // if the call is successful
      if (x == 5) {
        resolve(1); // returns the value 1
      } else {
        x++; // we increment the value of the counter
        console.log("not solved yet");
        loop(resolve, reject);
      }
    }, 5000); // (waits for 5 seconds)
  }
  return new Promise(loop);
}

Side note 2: Since you're using Promise, I take it you're targeting modern environments. That being the case, you might consider using fetch (which returns a native promise) rather than $.ajax, which returns a jQuery jqXHR object which is somewhat Promise-compatible.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Thank you for this clear answer, I've just tried that and it works. Thank you for the explanation as well, that's true I didn't add a catch block which necessary. thank you again – iliasse Feb 25 '19 at 12:03