服务器使用AngularJS进行轮询
我正在学习AngularJS。 我第一次尝试每秒都能获得新的数据:
'use strict'; function dataCtrl($scope, $http, $timeout) { $scope.data = []; (function tick() { $http.get('api/changingData').success(function (data) { $scope.data = data; $timeout(tick, 1000); }); })(); };
当我通过睡眠线程5秒来模拟慢速服务器时,它会在更新UI之前等待响应,并设置另一个超时。 问题是,当我重写上述使用Angular模块和DI创build模块:
'use strict'; angular.module('datacat', ['dataServices']); angular.module('dataServices', ['ngResource']). factory('Data', function ($resource) { return $resource('api/changingData', {}, { query: { method: 'GET', params: {}, isArray: true } }); }); function dataCtrl($scope, $timeout, Data) { $scope.data = []; (function tick() { $scope.data = Data.query(); $timeout(tick, 1000); })(); };
这只适用于服务器响应速度快的情况。 如果有任何延迟,它会在一秒钟内发出一个请求,而不会等待响应,并且似乎清除了用户界面。 我想我需要使用callback函数。 我试过了:
var x = Data.get({}, function () { });
但得到一个错误:“错误:destination.push不是一个函数”这是基于$资源的文档,但我真的不明白在那里的例子。
我如何使第二种方法工作?
您应该在callback中调用tick
函数进行query
。
function dataCtrl($scope, $timeout, Data) { $scope.data = []; (function tick() { $scope.data = Data.query(function(){ $timeout(tick, 1000); }); })(); };
更新的angular度版本引入了$ interval ,它比服务器轮询的$ timeout更好。
var refreshData = function() { // Assign to scope within callback to avoid data flickering on screen Data.query({ someField: $scope.fieldValue }, function(dataElements){ $scope.data = dataElements; }); }; var promise = $interval(refreshData, 1000); // Cancel interval on page changes $scope.$on('$destroy', function(){ if (angular.isDefined(promise)) { $interval.cancel(promise); promise = undefined; } });
这是我的版本使用recursion轮询。 这意味着它会在启动下一个超时之前等待服务器响应。 另外,当发生错误时,它会继续轮询,但在一个更宽松的庄园,并根据错误的持续时间。
演示在这里
在这里写更多关于它
var app = angular.module('plunker', ['ngAnimate']); app.controller('MainCtrl', function($scope, $http, $timeout) { var loadTime = 1000, //Load the data every second errorCount = 0, //Counter for the server errors loadPromise; //Pointer to the promise created by the Angular $timout service var getData = function() { $http.get('http://httpbin.org/delay/1?now=' + Date.now()) .then(function(res) { $scope.data = res.data.args; errorCount = 0; nextLoad(); }) .catch(function(res) { $scope.data = 'Server error'; nextLoad(++errorCount * 2 * loadTime); }); }; var cancelNextLoad = function() { $timeout.cancel(loadPromise); }; var nextLoad = function(mill) { mill = mill || loadTime; //Always make sure the last timeout is cleared before starting a new one cancelNextLoad(); $timeout(getData, mill); }; //Start polling the data from the server getData(); //Always clear the timeout when the view is destroyed, otherwise it will keep polling $scope.$on('$destroy', function() { cancelNextLoad(); }); $scope.data = 'Loading...'; });
我们可以使用$ interval服务轻松地进行轮询。 这里是关于$ interval的详细文档
https://docs.angularjs.org/api/ng/service/$interval
使用$ interval的问题是,如果您正在执行$ http服务调用或服务器交互,并且如果延迟超过$ interval时间,那么在您的一个请求完成之前,它会启动另一个请求。
解:
1.轮询应该是简单的状态从服务器得到像一个单一位或轻量级的JSON,所以不应该花更长的时间,然后定义的间隔时间。 你还应该定义时间间隔,以避免这个问题。
2.不知何故,它仍然是由于任何原因发生的,你应该检查一个全局标志,以前的请求完成或没有发送任何其他请求之前。 它会错过那个时间间隔,但不会提前发送请求。
另外,如果你想设置阈值,无论如何应该设置轮询值,那么你可以按照以下方式进行轮询。
这是工作的例子。 在这里详细解释
angular.module('myApp.view2', ['ngRoute']) .controller('View2Ctrl', ['$scope', '$timeout', '$interval', '$http', function ($scope, $timeout, $interval, $http) { $scope.title = "Test Title"; $scope.data = []; var hasvaluereturnd = true; // Flag to check var thresholdvalue = 20; // interval threshold value function poll(interval, callback) { return $interval(function () { if (hasvaluereturnd) { //check flag before start new call callback(hasvaluereturnd); } thresholdvalue = thresholdvalue - 1; //Decrease threshold value if (thresholdvalue == 0) { $scope.stopPoll(); // Stop $interval if it reaches to threshold } }, interval) } var pollpromise = poll(1000, function () { hasvaluereturnd = false; //$timeout(function () { // You can test scenario where server takes more time then interval $http.get('http://httpbin.org/get?timeoutKey=timeoutValue').then( function (data) { hasvaluereturnd = true; // set Flag to true to start new call $scope.data = data; }, function (e) { hasvaluereturnd = true; // set Flag to true to start new call //You can set false also as per your requirement in case of error } ); //}, 2000); }); // stop interval. $scope.stopPoll = function () { $interval.cancel(pollpromise); thresholdvalue = 0; //reset all flags. hasvaluereturnd = true; } }]);