Serveur interrogé avec AngularJS

J'essaie d'apprendre AngularJS. Ma première tentative d'obtenir de nouvelles données toutes les secondes a fonctionné:

'use strict'; function dataCtrl($scope, $http, $timeout) { $scope.data = []; (function tick() { $http.get('api/changingData').success(function (data) { $scope.data = data; $timeout(tick, 1000); }); })(); }; 

Lorsque je simule un serveur lent en dormant le fil pendant 5 secondes, il attend la réponse avant de mettre à jour l'interface utilisateur et de définir un autre délai d'attente. Le problème est lorsque j'ai réécrit ce qui précède pour utiliser les modules angulaires et les DI pour la création du module:

 '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); })(); }; 

Cela ne fonctionne que si la réponse du serveur est rapide. S'il y a un délai, il diffuse 1 requête une seconde sans attendre une réponse et semble effacer l'interface utilisateur. Je pense que je dois utiliser une fonction de rappel. J'ai essayé:

 var x = Data.get({}, function () { }); 

Mais a eu une erreur: "Erreur: destination.push n'est pas une fonction" Ceci était basé sur les documents pour $ resource mais je ne comprenais pas vraiment les exemples là-bas.

Comment puis-je faire fonctionner la deuxième approche?

Vous devriez appeler la fonction de tick dans le rappel pour la query .

 function dataCtrl($scope, $timeout, Data) { $scope.data = []; (function tick() { $scope.data = Data.query(function(){ $timeout(tick, 1000); }); })(); }; 

Les versions plus récentes de angular ont introduit un intervalle de $ qui fonctionne même mieux que $ timeout pour le sondage du serveur.

 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; } }); 

Voici ma version à l'aide d'un sondage récursif. Cela signifie qu'il attendra la réponse du serveur avant de lancer le prochain délai d'attente. De plus, en cas d'erreur, il continuera à voter mais dans un manoir plus détendu et selon la durée de l'erreur.

Demo est ici

En savoir plus ici

 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...'; }); 

Nous pouvons le faire rapidement en utilisant un service d'intervalle $. Voici un document détaillé sur l'intervalle $
https://docs.angularjs.org/api/ng/service/$interval
Le problème à l' aide de l'intervalle $ est que si vous effectuez un appel de service ou une interaction du serveur $ $ et si vous avez retardé plus d'un intervalle d'intervalle de temps, avant que votre demande ne soit terminée, cela déclenchera une autre requête.
Solution:
1. Le sondage devrait être un statut simple obtenant du serveur comme un seul bit ou un json léger, donc ne devrait pas prendre plus longtemps que votre intervalle d'intervalle défini. Vous devriez également définir le temps d'intervalle de manière appropriée pour éviter ce problème.
2. D'une manière ou d'une autre, cela se produit en raison de toute raison, vous devez vérifier un drapeau global que la demande précédente a terminé ou non avant d'envoyer d'autres demandes. Il manquera cet intervalle de temps, mais il n'émettra pas de demande prématurément.
De plus, si vous vouliez définir une valeur de seuil qui, après une certaine valeur, devrait être définie, vous pouvez le faire de la manière suivante.
Voici un exemple de travail. Expliqué en détail ici

 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; } }]);