angular-pxy

Per-scope promise proxy for Angular

Overview

angular-pxy extends scope objects with a $pxy() method that proxies promises through a Pxy instance that is automatically invalidated when the scope is destroyed. This helps prevent:

  • Pending asynchronous operations from causing side effects after the scope in which they were initiated is destroyed (e.g. an HTTP fetch continuing to exercise the backend, then returning a large payload, and then updating an object long after the scope is abandoned).
  • The hassle of explicitly cancelling pending operations (e.g. a timeout or interval).

Head over to Pxy documentation for a more detailed explanation of the use cases.

Download

Grab the latest from GitHub or use your favorite package manager:

Via Bower

bower install angular-pxy

Via NPM

npm install angular-pxy

Usage

Include angular-pxy.js in your application, after Angular is included.

<script src="path/to/angular.js"></script>
<script src="path/to/angular-pxy.js"></script>

You may use an AMD or CommonJS loader as well.

Initialize your Angular application with the mp.pxy module as a dependency:

angular.module('app', [ 'mp.pxy' ]);

Find instances where you're initiating asynchronous operations and getting back promises. You might also have some code for explicitly cancelling pending timers:

var fetch = $http.get(...),
    timeout = $timeout(...);

fetch.then(function () {
    // Will still get called after the scope is destroyed
}, function () {
    // Will still get called after the scope is destroyed
});

timeout.then(function () {
    // Will still get called after the scope is destroyed
    timeout = null;
});

// Cleanup boilerplate
$scope.$on('$destroy', function () {
    if (timeout) {
        $timeout.cancel(timeout);
    }
});

Use the $pxy() scope method to bind them to the scope's lifetime and get back proxies. The proxies work exactly the same way as your original promises:

var fetch = $scope.$pxy($http.get(...)),
    timeout = $scope.$pxy($timeout(...));

fetch.then(function () {
    // Won't get called after the scope is destroyed
}, function () {
    // Won't get called after the scope is destroyed
});

timeout.then(function () {
    // Won't get called after the scope is destroyed
    timeout = null;
});

// Scope $destroy handler is no longer needed
// The timer will automatically get cancelled

When the scope is destroyed, angular-pxy will automatically invalidate the Pxy instance and also cancel any promises that originate from the $timeout and $interval services.

You can also define custom promise cancellation recipes by tapping into $pxyProvider at the configuration phase of your application:

app.config([ '$pxyProvider', function ($pxyProvider) {
    $pxyProvider.onCancelPromise = function (promise) {
        // Cancel underlying asynchronous operation via app-specific
        // cancellation mechanism if the promise is recognized
        if (isProprietaryOperationPromise(promise)) {
            cancelProprietaryOperation(promise);
            // Return true to prevent default promise cancellation checks
            return true;
        }
    };
}]);

License

MIT