AngularJS全球http轮询服务

问题描述:

我正在使用AngularJS构建一个web应用程序。该应用需要轮询一个返回JSON数据的URL,并将该数据提供给该应用的任何部分。从我目前阅读的内容来看,我最好的选择是创建一个服务来处理轮询并保留其自己的JSON数据的内部缓存,然后将该服务注入想要查阅该数据的应用程序的任何部分。我失去的是如何真正去做这件事。我发现的最接近的例子是this question,但它似乎是创建一个由特定控制器(它本身绑定到给定路由)手动调用的服务,而我想要永久运行在应用程序背景中的东西永远不管应用的哪一部分是活动的。这是可行的,还是我采取了完全错误的方法?AngularJS全球http轮询服务

这里我的解决办法:

app.factory('Poller', function($http, $timeout) { 
    var data = { response: {}, calls: 0 }; 
    var poller = function() { 
    $http.get('data.json').then(function(r) { 
     data.response = r.data; 
     data.calls++; 
     $timeout(poller, 1000); 
    });  
    }; 
    poller(); 

    return { 
    data: data 
    }; 
}); 

(电话只是为了显示轮询已完成)

http://plnkr.co/edit/iMmhXTYweN4IrRrrpvMq?p=preview

编辑:随着约什大卫·米勒在意见提出,依赖于这个应该在app.run块中添加服务以确保从开始执行轮询:

app.run(function(Poller) {}); 

并且还在上次调用完成后移动了下一轮的调度。因此,如果投票长时间挂起,那么不会有“堆叠”电话。

更新的重击器。

+2

+1但是他想要的东西总是运行,因此也从'app.run' BLO触发它确保它从一开始就运行。我还会检查'poller'函数以确保先前调用'$ http'完成,所以它们不会无限累积,但似乎没有办法通过AngularJS的承诺实现。 – 2013-02-18 23:53:41

+1

Thnx。两个项目都加入了答案。关于堆叠可以通过简单地将下一个轮询的时间安排移动到先前呼叫的“随后”来避免。不是吗? – 2013-02-19 09:28:01

+1

太棒了! :-)我想我非常关注'isFulfilled()'的原始'q'的承诺方法,即'$ q'没有实现,我错过了完全明显的。大声笑 – 2013-02-19 18:45:34

以下是Github上的angular poller service,它可以很容易地注入到控制器中。

要安装: bower install angular-poller

既然你想开始在后台一直运行一个全球性的查询服务,你可以这样做:

// Inject angular poller service. 
var myModule = angular.module('myApp', ['poller']); 

// The home/init controller when you start the app. 
myModule.controller('myController', function($scope, $resource, poller) { 

    // Define your resource object. 
    var myResource = $resource(url[, paramDefaults]); 

    // Create and start poller. 
    var myPoller = poller.get(myResource); 

    // Update view. Most likely you only need to define notifyCallback. 
    myPoller.promise.then(successCallback, errorCallback, notifyCallback); 
}); 

现在,它会在后台,直到调用myPoller.stop()poller.stopAll()运行永远。

如果您想使用此轮询其他控制器的回调数据,你可以简单地做:

myModule.controller('anotherController', function($scope, $resource, poller) { 

    /* 
    * You can also move this to a $resource factory and inject it 
    * into the controller so you do not have to define it twice. 
    */ 
    var sameResource = $resource(url[, paramDefaults]); 

    /* 
    * This will not create a new poller for the same resource 
    * since it already exists, but will simply restarts it. 
    */ 
    var samePoller = poller.get(sameResource); 

    samePoller.promise.then(successCallback, errorCallback, notifyCallback); 
}); 
+0

它看起来像一个伟大的图书馆。有什么样的应用程序吗? – ardochhigh 2014-04-02 21:35:12

+0

@ardochhigh我打算很快添加一个示例应用程序。但在此之前,您可以检出[readme](https://github.com/emmaguo/angular-poller/blob/master/README.md)页面。 :-) – 2014-04-02 22:08:12

+0

谢谢@Emma Guo README页面非常详细。我对Angular相当陌生,但仍然对一些概念感到困惑。您的图书馆看起来非常适合我的要求也许我会试着做一个重要的概念证明。我会告诉你。 – ardochhigh 2014-04-03 08:06:53

我分叉@ ValentynShybanov的工厂代码并添加间隔调用(每秒,每5秒,等),你也可以停止和启动轮询如你所愿:

http://plnkr.co/edit/EfsttAc4BtWSUiAU2lWf?p=preview

app.factory('Poller', function($http, $timeout) { 
    var pollerData = { 
    response: {}, 
    calls: 0, 
    stop: false 
    }; 

    var isChannelLive = function() { 
    $http.get('data.json').then(function(r) { 
     if (pollerData.calls > 30 && pollerData.stop === false) { // call every minute after the first ~30 secs 
     var d = new Date(); 
     console.log('> 30: ' + d.toLocaleString() + ' - count: ' + pollerData.calls); 
     pollerData.calls++; 
     $timeout(isChannelLive, 10000); 
     } else if (pollerData.calls > 15 && pollerData.calls <= 30 && pollerData.stop === false) { // after the first ~15 secs, then call every 5 secs 
     var d = new Date(); 
     console.log('> 15 & <= 30: ' + d.toLocaleString() + ' - count: ' + pollerData.calls); 
     pollerData.calls++; 
     $timeout(isChannelLive, 5000); 
     } else if (pollerData.calls <= 15 && pollerData.stop === false) { // call every 1 second during the first ~15 seconds 
     var d = new Date(); 
     console.log('<= 15: ' + d.toLocaleString() + ' - count: ' + pollerData.calls); 
     pollerData.calls++; 
     $timeout(isChannelLive, 1000); 
     } 

     pollerData.response = r.data; 
    }); 

    }; 
    var init = function() { 
    if (pollerData.calls === 0) { 
     pollerData.stop = false; 
     isChannelLive(); 
    } 
    }; 
    var stop = function() { 
    pollerData.calls = 0; 
    pollerData.stop = true; 
    }; 

    return { 
    pollerData: pollerData, // this should be private 
    init: init, 
    stop: stop 
    }; 
});