How to get the status of angular $interval - check

2019-02-07 10:29发布

问题:

I am new to Angular (and JS) and just a little confused.

I start a timer with :

var getOverviewMapTimer = $interval($scope.UpdateOverviewMap, UPDATE_FREQUENCY); 

and, if I understand it, getOverviewMapTimer is a "promise".

I want to be able to check if the timer is running & had excepted that if I ever
$interval.cancel(getOverviewMapTimer); then getOverviewMapTimer would be null and I could check for that.

This seems not to be the case.

Do I have to explicitly destroy the promise (what goo is a promise to timer that has been cancelled?).? If so, how & would I then have to explicitly set it to null?

I think that I should use cancel(getOverviewMapTimer);, but am not 100% sure as getOverviewMapTimer is still non-null afterwards.

Thanks for your help

回答1:

After var getOverviewMapTimer = $interval(...); getOverviewMapTimer holds a reference to an object (that happens to be a promise).

Doing $interval.cancel(getOverviewMapTimer) passes (and cancels) the object referenced by the getOverviewMapTimer variable, but there is no way to convert an object to null. The getOverviewMapTimer variable will continue to hold a reference to the promise object and the only way to set it to null is through a new assignment (i.e. explicitely setting it to null):

var getOverviewMapTimer = $interval(...);
...
$interval.cancel(getOverviewMapTimer);
getOverviewMapTimer = null;

Advanced Topic:

It sounds indeed nice to have an easy way to find out if an interval-promise has been cancelled or not (e.g. adding a custom cancelled property to the promise object and setting its value to true when cancelling the interval).
Angular is cool enough to be incredibly flexible and extensible, so using the concept of a Service Decorator we are able to "augment" the $interval service, extending its cancel() method to add a cancelled property and setting its value to true when cancelling an interval-promise:

/* Service Decorators can be configured in `config` blocks */
app.config(function ($provide) {

    /* Register a decorator for the `$interval` service */
    $provide.decorator('$interval', function ($delegate) {

        /* Keep a reference to the original `cancel()` method */
        var originalCancel = $delegate.cancel;

        /* Define a new `cancel()` method */
        $delegate.cancel = function (intervalPromise) {

            /* First, call the original `cancel()` method */
            var retValue = originalCancel(intervalPromise);

            /* If the promise has been successfully cancelled,
             * add a `cancelled` property (with value `true`) */
            if (retValue && intervalPromise) {
                intervalPromise.cancelled = true;
            }

            /* Return the value returned by the original method */
            return retValue;
        };

        /* Return the original (but "augmented") service */
        return $delegate;
    });
});

Now, we can use the $interval service as usual and we can always check an interval-promise's cancelled property to find out if it has been cancelled.

var getOverviewMapTimer = $interval(...);
...
console.log(!!getOverviewMapTimer.cancelled);   // false
$interval.cancel(getOverviewMapTimer);
console.log(!!getOverviewMapTimer.cancelled);   // true

See, also, this short demo.



回答2:

It's technically impossible that getOverviewMapTimer is null after calling $interval.cancel(getOverviewMapTimer);.

If you want it to be null you have to do it yourself. Either immediately after cancelling the interval or via callback:

if ($interval.cancel(getOverviewMapTimer)) {
  getOverviewMapTimer = null;
}

or

var getOverviewMapTimer = $interval($scope.UpdateOverviewMap, UPDATE_FREQUENCY);
getOverviewMapTimer.catch(function() { getOverviewMapTimer = null; }); 

Be aware, though, that the callback is asynchronous.



回答3:

easy

var interval = $interval(function() { }, 1000);
console.log(interval.$$state.status); //0

$interval.cancel(interval);
console.log(interval.$$state.status); //2

if(interval.$$state.status == 0)
    //valid
else
    //invalid