Default behavior if no other functions chained to

2019-02-26 02:36发布

问题:

I want to open a 'confirm you want to cancel dialog', and if no other functions are chained up, then default to navigating back a page ($window.history.back();).

This is how I might do it if I was passing in a callback:

function openCancelModal(form, callback) {
     if (form.$dirty) {
         var message = '...';
         modalThingy.open(message).then(callback || default);
     }

     function default() {
         $window.history.back();
     }
}

However that swallows the power (coolness) of using promises.

Is there a way of returning a promise, but if nothing is chained to it then call a default function?

I am using angularjs, but I imagine there is a generic answer to this problem.

回答1:

Is there a way of returning a promise, but if nothing is chained to it then call a default function?

At the point you are returning the promise from the function, the caller has not even seen the promise object yet so it has had no opportunity to even see what the caller will or won't do after the promise is returned so nothing can be set up or seen in advance before you return the promise.

In addition, standard promise objects do not provide any means of querying what handlers are or are not attached.


There are some hackish things that could be done (though I don't think I'd recommend them).

For example, you could override .then() on the promise you are returning so that you will be able to see if it gets called before the promise is resolved and you could keep track of that info in your own state. Then, when the promise does get resolved, if .then() has not yet been called, you could execute your default behavior.

Here's an outline of that sort of hackish scheme:

function someAsync() {
    var foundThenHandler = false;
    var p = new Promise(function(resolve, reject) {
        // some code that eventually and asynchronously
        // calls resolve or reject


        // as long as the code here executes some time in the future
        // after the caller has seen the returned promise and had a chance to 
        // add its own .then() handlers, then the code can check the
        // foundThenHandler variable to see if .then() was ever called on it

        // For example:
        setTimeout(function() {
            resolve();
            if (!foundThenHandler) {
               // carry out some default action
            }
        }, 1000);
    });
    var oldThen = p.then;
    p.then = function(resolveHandler, rejectHandler) {
        foundThenHandler = true;
        return oldThen.apply(p, arguments);
    }
    return p;
}


someAsync().then(function(val) {
    // async operation finished, default action will not be triggered
});

// no .then() handler attached, default action will be triggered
someAsync();