Wenn ich einen langsamen Server simuliere, indem ich den Thread 5 Sekunden lang in den Ruhezustand versetze, wartet er auf die Antwort, bevor er die Benutzeroberfläche aktualisiert und ein weiteres Timeout festlegt. Das Problem ist, als ich das Obige umgeschrieben habe, um Angular-Module und DI für die Modulerstellung zu verwenden:
Dies funktioniert nur, wenn die Serverantwort schnell ist. Wenn es zu Verzögerungen kommt, spammt es 1 Anfrage pro Sekunde aus, ohne auf eine Antwort zu warten, und scheint die Benutzeroberfläche zu löschen. Ich denke, ich muss eine Callback-Funktion verwenden. Ich habe es versucht:
var x = Data.get({}, function () { });
bekam aber einen Fehler: “Error: destination.push is not a function” Dies basierte auf den Dokumenten für $ressource aber ich habe die Beispiele dort nicht wirklich verstanden.
Wie lasse ich den zweiten Ansatz funktionieren?
Sie sollten anrufen tick Funktion im Callback für query.
Großartig, danke. Ich wusste nicht, dass man den Rückruf dort platzieren kann. Damit war das Spam-Problem gelöst. Ich habe auch die Datenzuweisung in den Callback verschoben, wodurch das UI-Clearing-Problem gelöst wurde.
– David
2. Dezember 2012 um 17:25 Uhr
Angenommen, der obige Code gilt für pageA und controllerA. Wie stoppe ich diesen Timer, wenn ich zu pageB und controllerB navigiere?
– Varun Verma
21. November 2013 um 10:46 Uhr
Der Prozess zum Stoppen eines $timeouts wird hier erklärt docs.angularjs.org/api/ng.$timeout. Grundsätzlich gibt die $timeout-Funktion ein Versprechen zurück, das Sie einer Variablen zuweisen müssen. Hören Sie dann, wann dieser Controller zerstört wird: $scope.$on(‘destroy’, fn());. Rufen Sie in der Callback-Funktion die Cancel-Methode von $timeout auf und übergeben Sie das gespeicherte Promise: $timeout.cancel(timeoutVar); Die $interval-Dokumente haben tatsächlich ein besseres Beispiel (docs.angularjs.org/api/ng.$interval)
– Justin Lukas
15. Januar 2014 um 0:57 Uhr
@JustinLucas, nur für den Fall, dass es $scope.$on(‘$destroy’, fn()) sein sollte;
– Tomate
1. Juli 2014 um 2:18 Uhr
Was ist der beste Weg, um diesen Ansatz zu “stoppen”, sobald ein Ereignis auf meiner Seite auftritt. Ich brauche diesen Thread wirklich, wenn der Benutzer auf einer bestimmten Seite ist. Irgendeine Idee?
– halbano
23. Dezember 2014 um 20:26 Uhr
Bob
Neuere Versionen von eckig wurden eingeführt $Intervall das funktioniert noch besser als $Zeitüberschreitung für die Serverabfrage.
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;
}
});
-1, ich denke nicht, dass $interval geeignet ist, da Sie nicht auf die Serverantwort warten können, bevor Sie die nächste Anfrage senden. Dies kann zu zu vielen Anfragen führen, wenn der Server eine hohe Latenz hat.
– Treu
29. Januar 2014 um 16:17 Uhr
@Treur: Auch wenn das heutzutage gängige Weisheit zu sein scheint, bin ich mir nicht sicher, ob ich dem zustimme. In den meisten Fällen hätte ich lieber eine widerstandsfähigere Lösung. Betrachten Sie den Fall, in dem ein Benutzer vorübergehend offline geht, oder das Extrem Ihres Falls, in dem der Server nicht auf eine einzige Anfrage antwortet. Die Benutzeroberfläche wird für Benutzer von $timeout nicht mehr aktualisiert, da kein neues Timeout festgelegt wird. Für Benutzer von $interval fährt die Benutzeroberfläche dort fort, wo sie aufgehört hat, sobald die Verbindung wiederhergestellt ist. Natürlich ist es auch wichtig, vernünftige Verzögerungen auszuwählen.
– Bob
30. Januar 2014 um 2:58 Uhr
Ich denke, es ist bequemer, aber nicht belastbar. (Eine Toilette in meinem Schlafzimmer ist auch nachts sehr praktisch, aber irgendwann fängt sie an, schlecht zu riechen 😉 ) Wenn Sie aktuelle Daten mit $interval abrufen, ignorieren Sie das Ergebnis des Servers. Hier fehlt eine Methode, um Ihren Benutzer zu informieren, die Datenintegrität zu erleichtern oder kurz: Ihren Anwendungsstatus im Allgemeinen zu verwalten. Sie könnten jedoch gängige $http-Interceptoren dafür verwenden und das $interval abbrechen, wenn dies geschieht.
– Treu
30. Januar 2014 um 8:34 Uhr
Wenn Sie $q Promises verwenden, können Sie einfach den finally-Rückruf verwenden, um sicherzustellen, dass die Abfrage fortgesetzt wird, unabhängig davon, ob die Anfrage fehlschlägt oder nicht.
– Tyson Nero
25. April 2014 um 18:48 Uhr
Eine bessere Alternative wäre, nicht nur das Erfolgsereignis, sondern auch das Fehlerereignis zu behandeln. Auf diese Weise können Sie die Anfrage erneut versuchen, wenn sie fehlschlägt. Sie können es sogar in einem anderen Intervall tun …
– Erdnuss
16. Oktober 2014 um 14:41 Uhr
Hier ist meine Version mit rekursiver Abfrage. Das heißt, es wird auf die Serverantwort gewartet, bevor das nächste Timeout eingeleitet wird. Auch wenn ein Fehler auftritt, wird die Abfrage fortgesetzt, jedoch entspannter und entsprechend der Dauer des Fehlers.
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...";
});
Wir können es einfach mit dem Dienst $interval abfragen. Hier ist ein Detaildokument über $interval
Problem Die Verwendung von $interval bedeutet, dass, wenn Sie einen $http-Dienst aufrufen oder eine Serverinteraktion ausführen und wenn die Verzögerung mehr als $interval beträgt, eine andere Anforderung gestartet wird, bevor Ihre eine Anforderung abgeschlossen ist.
Lösung:
1. Die Abfrage sollte ein einfacher Status sein, der vom Server abgerufen wird, z. B. ein einzelnes Bit oder ein leichtgewichtiger JSON, und sollte daher nicht länger als Ihre definierte Intervallzeit dauern. Sie sollten auch die Intervallzeit entsprechend definieren, um dieses Problem zu vermeiden.
2. Irgendwie passiert es aus irgendeinem Grund immer noch, Sie sollten ein globales Flag überprüfen, das die vorherige Anfrage abgeschlossen hat oder nicht, bevor Sie andere Anfragen senden. Es wird dieses Zeitintervall verpassen, aber es wird die Anfrage nicht vorzeitig senden.
Auch wenn Sie einen Schwellenwert festlegen möchten, nach dem nach einem bestimmten Wert sowieso die Abfrage festgelegt werden soll, können Sie dies auf folgende Weise tun.
Hier ist ein funktionierendes Beispiel. ausführlich erklärt hier
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;
}
}]);
11534000cookie-checkServer-Polling mit AngularJSyes