0

I am trying to chain 3 promises. I find that if I resolve promise1, I get the result in the promise2's success callback and I can control what and if I need to send anything to promise3.
But if I issue a notify in promise1, not matter what I do in promise2, the promise3's notifyCallback ALWAYS get triggered immediately. How can I prevent it and make it conditional based on some business rules in promise2 ?

Here is a simple example in jsfiddle: http://jsfiddle.net/deepfiddle/rxv8322s/

If you issue .notify() instead of .resolve() (uncomment/comment the line in promise1), you will see what promise3 gets notified immediately. Here is the relevant code:

var myApp = angular.module('myApp', []);

myApp.controller('myCtrl', function($scope, $q, $timeout) {
console.log("--app controller");

var p0 = $q.when();
p0
.then( //Promise: p1
    function(result) {
        console.log("p1", result);
        var deferred = $q.defer();
        $timeout(function() {
            console.log("in timeout of p1");
            //Note1: Propagation of resolve can be controlled but not notify
            //       Uncomment notify instead to see the difference on the console
            deferred.resolve("p1 resolved by timeout 2000");
            //deferred.notify("p1 notified by timeout 2000");
        }, 2000);
        return deferred.promise;
    }
)
.then(//Promise: p2
    function(result) {
        console.log("p2-onsuccess:", result);
        var deferred = $q.defer();
         $timeout(function() {
            console.log("in timeout of p2");
            deferred.resolve("p2 resolved by timeout 2000");
        }, 2000);           
        return deferred.promise;
    }, 
    null,
    function(result) {
        //Note2: Unable to prevent propagation of p1.notify() to p3
        console.log("p2-onnotify:", result);
        var deferred = $q.defer();
        $timeout(function() {
            console.log("in timeout of p2");
            deferred.notify("p2 notified by timeout 2000");
        }, 2000);            
        return deferred.promise;
    }
)
.then(//Promise:p3
    function(result) {
        console.log("p3-onsuccess:", result);
    },
    null,
    function(result) {
        console.log("p3-onnotify:", result);            
    }
)
});
deeSo
  • 40
  • 5
  • You could try my module for chaining promises: https://github.com/rangelier/promise – Rob Angelier Apr 25 '15 at 19:43
  • I see what you mean. Check out http://stackoverflow.com/questions/16335597/jquery-deferred-cancel-progress . Throwing a deliberate error seems to stop the chain but returning an unresolved promise doesn't seem to. – Derek Apr 25 '15 at 20:00
  • Just curious: what do you want to use progress events in your app for? Many promise libraries have deprecated them (just for the reason that they are hard to deal with) – Bergi Apr 25 '15 at 20:15
  • Inb4 notification is broken don't use it. – Benjamin Gruenbaum Apr 26 '15 at 11:51
  • @RobAngelier - your module does not address the notification issue - seems to be a convenience wrapper around $http – deeSo Apr 26 '15 at 14:11
  • @Derek The link you gave only addresses resolve() , not notify(). I already tried with notify and it does not seem to control it. If you have a jsfiddle example, that would be great. – deeSo Apr 26 '15 at 14:13
  • @Bergi I have to use notify since i get a promise from an external source that only uses notify. – deeSo Apr 26 '15 at 14:14
  • So it seems like a bug in Angular ? I can stop a resolve() from propagating down the promise chain but I cannot stop a notify(). Is there any workaround or hacky way somebody can suggest where I still use the notify callback but somehow stop propagation ? – deeSo Apr 26 '15 at 14:15
  • What do you mean by "only uses notify"? What exactly is it used for? And no, it's not a bug in angular, it's by design. You can use the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572) to work around it if you must. – Bergi Apr 26 '15 at 17:57
  • @Bergi Thank you ! The deferred antipattern works. But can you explain why it was designed that way ? – deeSo Apr 27 '15 at 02:24
  • @Bergi Thank you ! The deferred antipattern works. But I need to understand the concept. By 'only uses notify', I mean, the promise2 in my code above is a third party written promise that does not .resolve() but does a notify() everytime a business condition is met. But that messes me up in my code since I have a few promises chained to it and they all get notified no matter what I do to stop the propagation. So can you explain why it was designed that way ? When p1, p2 and p3 are chained, and p1.notify() happens, I only expect the p2's notifyCallback to get triggered and not p3's as well. – deeSo Apr 27 '15 at 02:31
  • Notification was designed to be "global events on a promise chain". The subscriber could always get all events from everywhere below, and do with them as he wishes. Your third party code is completely **abusing promises** (as never-resolved promises should not be). I wonder why you are chaining `then` calls at all if they never resolve? I think what you really want is a stream library that triggers on every notification event, and lets you map and filter (and more) over the stream of "condition met" events. – Bergi Apr 27 '15 at 11:10

0 Answers0