angular1.x---angular中清除定时器$interval,解决重复计算问题

时间:2021-12-01 02:42:58

用angular1.x版本做定时器的时候,需要用到内置对象'$interval',用到window原生的setInterval的时候不能及时更新数据,但是’$interval’定义的定时器却不像setInterval那么容易清除。

———————————————————————-

查看源码,angular提供有例子进行说明定时器的清除:

<script>
* angular.module('intervalExample', [])
* .controller('ExampleController', ['$scope', '$interval',
* function($scope, $interval) {
* $scope.format = 'M/d/yy h:mm:ss a';
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
*
* var stop;
* $scope.fight = function() {
* // Don't start a new fight if we are already fighting
* if ( angular.isDefined(stop) ) return;
*
* stop = $interval(function() {
* if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
* $scope.blood_1 = $scope.blood_1 - 3;
* $scope.blood_2 = $scope.blood_2 - 4;
* } else {
* $scope.stopFight();
* }
* }, 100);
* };
*
* $scope.stopFight = function() {
* if (angular.isDefined(stop)) {
* $interval.cancel(stop);
* stop = undefined;
* }
* };
*
* $scope.resetFight = function() {
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
* };
*
* $scope.$on('$destroy', function() {
* // Make sure that the interval is destroyed too
* $scope.stopFight();
* });
* }])
* // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', ['$interval', 'dateFilter',
* function($interval, dateFilter) {
* // return the directive link function. (compile function not needed)
* return function(scope, element, attrs) {
* var format, // date format
* stopTime; // so that we can cancel the time updates
*
* // used to update the UI
* function updateTime() {
* element.text(dateFilter(new Date(), format));
* }
*
* // watch the expression, and update the UI on change.
* scope.$watch(attrs.myCurrentTime, function(value) {
* format = value;
* updateTime();
* });
*
* stopTime = $interval(updateTime, 1000);
*
* // listen on DOM destroy (removal) event, and cancel the next UI update
* // to prevent updating time after the DOM element was removed.
* element.on('$destroy', function() {
* $interval.cancel(stopTime);
* });
* }
* }]);
* </script>

一大串代码,似乎不太容易,远不止简单的设置timer=null就可以解决的,虽然可以实现,但是今天在公司项目中遇到了问题,无论如何仿照源码都无法解决问题,于是继续寻找并打印$interval源码:

function interval(fn, delay, count, invokeApply) {
var hasParams = arguments.length > 4,
args = hasParams ? sliceArgs(arguments, 4) : [],
setInterval = $window.setInterval,
clearInterval = $window.clearInterval,
iteration = 0,
skipApply = (isDefined(invokeApply) && !invokeApply),
deferred = (skipApply ? $$q : $q).defer(),
promise = deferred.promise;

count = isDefined(count) ? count : 0;

promise.then(null, null, (!hasParams) ? fn : function() {
fn.apply(null, args);
});

promise.$$intervalId = setInterval(function tick() {
deferred.notify(iteration++);

if (count > 0 && iteration >= count) {
deferred.resolve(iteration);
clearInterval(promise.$$intervalId);
delete intervals[promise.$$intervalId];
}

if (!skipApply) $rootScope.$apply();

}, delay);

intervals[promise.$$intervalId] = deferred;

return promise;
}
源码中,$interval定义一个定时器可以传入四个参数(fn, delay, count, invokeApply):
fn://定时器的执行函数
delay://每次函数执行的间隔时间
count://函数fn的执行次数
invokeApply://设置脏值检测

通过count的设置便解决今天项目中,数值无限减小问题,代码如下:

$scope.num=60;
$scope.timer=$interval(function(){
$scope.num--;
},1000,$scope.num);
///在切换控制器的时候,清除定时器,减少内存损耗
$scope.$on(
"$destroy",
function() {
$interval.cancel( $scope.timer);
}
);