Search code examples
promiseabortwhen-js

Abort a promise chain without raising an error


Using When.js, we have a situation where we want to quietly abort a promise chain mid way, due to the user changing their mind. Our current method is to simply never resolve that step of the chain - effectively leaving the other promises "hanging". This seems slightly dirty?

If we reject the promise, then of course our exception handlers kick in. We could work around that, using a custom message which we detect and ignore, but that also seems a bit unclean.

Is there a better approach?

This is what the code looks like:

    return getConfirmation(confirmConversion, 'Ready to upload your file to the ' + terria.appName + ' conversion service?')
        .then(function() { 
            return loadItem(createCatalogMemberFromType('ogr', terria), name, fileOrUrl); 
        });


function getConfirmation(confirmConversion, message) {
    ...
    var d = when.defer(); // there's no `when.promise(resolver)` in when 1.7.1
    PopupMessageConfirmationViewModel.open('ui', { 
        ...
        confirmAction: d.resolve,
        denyAction: function() { this.close(); /* Do nothing or d.reject(); ? */ }
    });
    return d.promise;
}

Result

For completeness, I changed the code to:

    confirmAction: function () { d.resolve(true); },
    enableDeny: true,
    denyAction: function() { this.close(); d.resolve(false); }

and

        .then(function(confirmed) { 
            return confirmed ? loadItem(createCatalogMemberFromType('ogr', terria), name, fileOrUrl) : undefined; 
        });

Solution

  • Making my comment into an answer:

    If you're trying to return three possible states (resolve, rejected and user cancelled) so your code can handle all three possible resolutions correctly and you're using promises, then you will have to make either the resolved value indicate that the user cancelled or the reject reason will have to indicate cancel and your code will have to check for that.

    There are only two possible final states for a promise, not three so you'll have to communicate the third state in one of the other two.

    I'd recommend not stranding promises in the pending state unless you're absolutely sure they won't lead to a memory leak, but even then it doesn't seem like a very clean design to just strand them.