在AngularJS工厂中使用setInterval

21

我尝试了AngularJS文档中的代码(在此处提供:http://jsfiddle.net/zGqB8/)。它实现了一个时间工厂并使用$timeout在每秒钟后更新时间对象。

angular.module('timeApp', [])
.factory('time', function($timeout) {
    var time = {};

    (function tick () {
        time.now = new Date().toString();
        $timeout(tick, 1000);  // how to do it using setInterval() ?
    })();

    return time;
});

如何使用setInterval()函数代替$timeout()函数实现相同的功能?我知道需要使用 scope.$apply()来进入angular执行上下文,但在工厂函数中该怎么用呢?我的意思是在控制器中我们有scope,但在工厂函数中没有scope。


为什么需要使用setInterval?这可以实现相同的结果。 - Liviu T.
4
我喜欢你现在的解决方案。 - Andrew Joslin
@LiviuT。是的,在这里它可以工作,但我想知道当在工厂函数内部时,如何进入角执行上下文。 - user183123
Angular现在有$interval:https://docs.angularjs.org/api/ng/service/$interval - Surreal Dreams
4个回答

38

你可以将$timeout用作一个时间间隔。

var myIntervalFunction = function() {
    cancelRefresh = $timeout(function myFunction() {
        // do something
        cancelRefresh = $timeout(myIntervalFunction, 60000);
    },60000);
};
如果视图被销毁,您可以通过监听$destroy来销毁它。
$scope.$on('$destroy', function(e) {
        $timeout.cancel(cancelRefresh);
});

9
我知道。目前在Angular中没有setInterval的替代方法。模拟它的唯一方式是使用$timeout函数并递归调用自身。 - asgoth
9
这里没有递归,因此不会发生任何栈溢出。 - bmm6o
@KevinBeal:“做点什么”,无论你的函数应该做什么。 - asgoth
这个答案会在第一次运行后等待双倍的时间。请查看我的下面的答案。超时是构建为在1分钟内运行。当1分钟到期时,它调用操作,然后创建一个定时器,在1分钟内执行。当那1分钟到期时,它创建一个新的定时器,在1分钟内运行。1分钟后,“something”发生,循环重复。第一次运行正常,随后的运行时间是等待时间的两倍(例如2分钟)。如果您将第4行(第二个$timeout)更改为1ms的超时,则可以解决问题,而不会引入潜在的堆栈溢出。 - Tyler Forsythe
3
@TylerForsythe 你是正确的,我撤回了一项错误的更改,将 myFunction 不正确地重命名为 myIntervalFunction。但是每个 $timeout 不会导致堆栈溢出问题,因为它不是递归调用,而是延迟执行提供的函数,并将在新的调用堆栈中执行。 - ljs
显示剩余2条评论

32

更新

Angular在1.2版本中实现了一个$interval特性 - http://docs.angularjs.org/api/ng.$interval


以下是旧版示例,除非您使用的版本早于1.2,否则请忽略。

Angular中的setInterval实现 -

我创建了一个名为timeFunctions的工厂,其中包含$setInterval和$clearInterval。

请注意,每当我需要在工厂中修改作用域时,我都会将其传递进去。我不确定这是否符合“Angular方式”,但它运行良好。

app.factory('timeFunctions', [

  "$timeout",

  function timeFunctions($timeout) {
    var _intervals = {}, _intervalUID = 1;

    return {

      $setInterval: function(operation, interval, $scope) {
        var _internalId = _intervalUID++;

        _intervals[ _internalId ] = $timeout(function intervalOperation(){
            operation( $scope || undefined );
            _intervals[ _internalId ] = $timeout(intervalOperation, interval);
        }, interval);

        return _internalId;
      },

      $clearInterval: function(id) {
        return $timeout.cancel( _intervals[ id ] );
      }
    }
  }
]);

使用示例:

app.controller('myController', [

  '$scope', 'timeFunctions',

  function myController($scope, timeFunctions) {

    $scope.startFeature = function() {

      // scrollTimeout will store the unique ID for the $setInterval instance
      return $scope.scrollTimeout = timeFunctions.$setInterval(scroll, 5000, $scope);

      // Function called on interval with scope available
      function scroll($scope) {
        console.log('scroll', $scope);
        $scope.currentPage++;

      }
    },

    $scope.stopFeature = function() {
      return timeFunctions.$clearInterval( $scope.scrollTimeout );
    }

  }
]);

4

你能调用一个普通的JavaScript方法,然后在该方法中包装Angular代码以使用$apply吗?

例子

timer = setInterval('Repeater()', 50);

var Repeater = function () {
  // Get Angular scope from a known DOM element
  var scope = angular.element(document.getElementById(elem)).scope();
  scope.$apply(function () {
    scope.SomeOtherFunction();
  });
};

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接