0

I'm facing an troublesome issue, because it does not occurs every time: I call webservices with angularJS (hosted in Django/Tastypie), with promises sothat WS2 (Web Service #2) is called only when WS1 has been successfully executed, etc.

The code looks like this:

myfunc = function() {
    callPromiseWS1()
    .then(function(data){
        callPromiseWS2()
    })
    .then(function(data){
        callPromiseWS3()
    })
};
  • WS2 is a POST request that writes stuff in Database.
  • WS3 is a POST request which uses stuff created by WS2.

Sometimes (and not always), WS3 fails because the object that should have been already created by WS2 does NOT exist.

Of course, if I try to execute the WS3 request later manually, it works.

I have the feeling that WS2 and WS3 are executed in parallel, that's not what I expect.

Any idea? Thank you.

David Dahan
  • 10,576
  • 11
  • 64
  • 137

2 Answers2

3

You're missing 3 return statements, but the behavior you're experiencing is because of one in particular:

myfunc = function() {
    return callPromiseWS1()
    .then(function(data){
        return callPromiseWS2();        // this one
    })
    .then(function(data){
        return callPromiseWS3();
    })
};

If you don't return the promise that callPromiseWS2 returns, the then() won't know that it's dealing with a promise and just move onto the next then as soon as the synchronous code in callPromiseWS2 completes.

Note that if you're not actually using the data parameter in each step (or if you're just going to pass it right into callPromiseWS2 and callPromiseWS3 as the only parameter), you can simplify this and eliminate the need for two of the above return statements and a lot of the code:

myfunc = function() {
    return callPromiseWS1()
    .then(callPromiseWS2)
    .then(callPromiseWS3);
};

Remember that any function that uses promises should either return the promise, or call .done() at the end.

As a matter of personal preference, I think it's a good idea to use a naming scheme for functions that return promises so that you know they return a promise that needs to be dealt with.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Thanks a lot for this explanation! It just confirms to me that it's a bad idea to use concepts I don't control on my code ;) – David Dahan Apr 24 '14 at 12:00
  • 1
    Glad to help. I agree that it's a good idea to have a good grasp on the things you use in your code, but I definitely recommend getting familiar with promises. I just started using them a month and a half ago, and they've already helped make my life a lot easier! :) – JLRishe Apr 24 '14 at 12:29
  • Heyhey. Just another quick question: do you know how to make a redirect and stop the promise chain? Currently, if I have a `$location.path('url')` (angularJS redirection) in the middle of the promises, the redirect occurs but the promise chain is fully executed. – David Dahan Apr 24 '14 at 13:17
  • I'm not familiar with angularJS, but from what I found, there isn't an easy way to simply break out of a promise chain. You could throw an exception, which would skip all `then()`s up to the next `catch()` (if there is one), or you can use an `if` statement to nest the logic and only run the later steps if you decide not to redirec. If you can create a new question with your current code and post a link here, I could have a look at it. – JLRishe Apr 24 '14 at 13:39
  • Thank you. http://stackoverflow.com/questions/23271907/using-redirections-into-promises-chain – David Dahan Apr 24 '14 at 14:31
2

I'm not an expert on promises (and maybe the code you posted was simplified), but the first thing I would check is that the first then returns something, or the second .then will have the same object returned by callPromiseWS1() to work on. I believe it should be something like:

callPromiseWS1()
    .then(function(data){
        return callPromiseWS2();
    })
    .then(function(data){
        return callPromiseWS3();
    })

But, as I said, I'm not an expert on promises and I don't know if it was just a simplified example of your structure.

Polmonite
  • 933
  • 6
  • 13
  • 2
    This is actually the correct answer. You are correct, promises only continue after the return value resolved. If the return value is undefined (no return) they continue immediately. If you return a promise they will unwrap it first. Of course, since data is not used this can be simplified to `callPromiseWS1().then(callPromiseWS2).then(callPromiseWS3);` You should probably phrase the first paragraph a bit better though, the second `.then` will have `undefined` to work with and will be executed without waiting for the first `then` if the `return` is omitted. – Benjamin Gruenbaum Apr 24 '14 at 11:29