50

I'm writing an angularjs app relying on promises, and though it's working, I wonder if I could do it more optimally.

At the beginning of the code, I'm creating a promise that goes off to fetch some data. When this is done, I want to run several functions that all use this data. The functions are attached at unrelated parts of the app, so I do not know the order in which they're attached to the promise. They do not need to be done in sequence either.

app.service("Fetch", function ($q){
    return function() {
        var def = $q.defer();
        somelibrary.asynccall(function(error, data){ //callback
            if (error) def.reject(error);
            else def.resolve(data);
        });
        return def.promise;
    };
});

app.controller("ctrl", function ($scope, Fetch) {
    var prom = Fetch();

    //somewhere:
    prom.then(function(data){$scope.var1 = data["VAR1"];});
    //somewhere else:
    prom.then(function(data){$scope.var2 = data["VAR2"]});
});

The main disadvantage here is that the later thens are only executed whenever the preceding ones are finished, which is not necessary here.

Also, I need to add return data inside every function(data){...}, otherwise the following then() does not have the data available.

Is there not another way to do this, more apt for this situation?


EDIT: as mentioned by @jfriend00, I was mistaken; in fact the 2 functions both run, in parallel, as soon as the promise is successfully resolved, and they are not chained and therefore not dependent on each other. Thanks for your help

ElRudi
  • 2,122
  • 2
  • 18
  • 33
  • 6
    With your pattern, the two `.then()` calls on the same promise are going to get called one after another when the promise is resolved. The second `.then()` has only to do with the original promise and nothing to do with what happens on the first `.then()`. These are not chained so the second `.then()` has no dependency upon what is returned from the first `.then()` and both will be passed the same data. They are just multiple watchers of the same promise kind of like two event handlers listening for the same event. – jfriend00 Aug 17 '14 at 02:07
  • jfriend00 is right, the context of your question does not relate to the code you have provided. Since your promises are not chained, then the `data` on your success callbacks are still from the original promise. `prom = Fetch();` – ryeballar Aug 17 '14 at 02:31
  • @jfriend00 you are right, they are in fact not chained! I should've seen that, thanks for clarifying! – ElRudi Aug 17 '14 at 03:14

2 Answers2

87

Turning my comment into an answer since it seems to clear up the issue:

With your pattern, the two .then() calls on the same promise are going to get called one after another when the promise is resolved. The second .then() has only to do with the original promise and nothing to do with what happens on the first .then().

These are not chained so the second .then() has no dependency upon what is returned from the first .then() and both will be passed the same data. They are just multiple watchers of the same promise kind of like two event handlers listening for the same event.

The two .then() handlers on the same promise will be called in the order they were attached to the promise and will both be passed the same data.

See these two answers:

Is there a difference between promise.then.then vs promise.then; promise.then

Understanding javascript promises; stacks and chaining

for more info on chaining p.then(...).then(...) vs. branching p.then(...); p.then(...) with promises.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 7
    " kind of like two event handlers listening for the same event" - actually it is _exactly_ two event handlers listening to the same event. – Benjamin Gruenbaum Aug 17 '14 at 06:46
3

You need parallel execution: $q.all()

$q.all(
    function1,
    function2,
    function3
).then(function(responses) {
    console.log(responses);
});
monkeyinsight
  • 4,719
  • 1
  • 20
  • 28
  • 2
    Thanks @monkeyinsight for replying. That's not what I'm trying to accomplish - I do not want to wait for >1 functions to finish before resolving the promise. Instead, I want to call multiple functions _upon resolving the promise_. I could do that by replacing the `console.log()` line in your code by multiple functions to do that, but I do not know in advance which these functions will be. I want to be able to add them from various sites in the app, and start them as soon as they're added, or as soon as the promise resolves (whichever comes later). – ElRudi Aug 17 '14 at 01:56
  • you want something like recursive `then`? – monkeyinsight Aug 17 '14 at 02:07