Saya mencoba mempelajari AngularJS. Upaya pertama saya untuk mendapatkan data baru setiap detik berhasil:
'use strict';
function dataCtrl($scope, $http, $timeout) {
$scope.data = [];
(function tick() {
$http.get('api/changingData').success(function (data) {
$scope.data = data;
$timeout(tick, 1000);
});
})();
};
Ketika saya mensimulasikan server yang lambat dengan menidurkan utas selama 5 detik, ia menunggu respons sebelum memperbarui UI dan menyetel waktu tunggu lain. Masalahnya adalah ketika saya menulis ulang di atas untuk menggunakan modul Angular dan DI untuk pembuatan modul:
'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);
})();
};
Ini hanya berfungsi jika respons server cepat. Jika ada penundaan, itu akan mengirimkan 1 permintaan per detik tanpa menunggu tanggapan dan tampaknya menghapus UI. Saya rasa saya perlu menggunakan fungsi panggilan balik. Saya mencoba:
var x = Data.get({}, function () { });
tetapi mendapat kesalahan: "Error: destination.push is not a function" Ini didasarkan pada dokumen untuk $ resource tetapi saya tidak benar-benar memahami contoh di sana.
Bagaimana cara membuat pendekatan kedua berhasil?
sumber
Versi angular yang lebih baru telah memperkenalkan $ interval yang bekerja lebih baik daripada $ timeout untuk polling server.
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; } });
sumber
Ini versi saya menggunakan polling rekursif. Yang berarti itu akan menunggu respon server sebelum memulai waktu tunggu berikutnya. Selain itu, jika terjadi kesalahan, pemungutan suara akan dilanjutkan tetapi dengan cara yang lebih santai dan sesuai dengan durasi kesalahan.
Demo ada di sini
Lebih banyak ditulis di sini
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...'; });
sumber
Kita bisa melakukan polling dengan mudah menggunakan $ interval service. berikut adalah detail dokumen tentang $ interval
https://docs.angularjs.org/api/ng/service/$interval
Masalah menggunakan $ interval adalah jika Anda melakukan panggilan layanan $ http atau interaksi server dan jika tertunda lebih dari $ interval waktu lalu sebelum satu permintaan Anda selesai, itu memulai permintaan lain.
Solusi:
1. Polling harus berupa status sederhana yang didapat dari server seperti bit tunggal atau json ringan sehingga tidak memakan waktu lebih lama dari waktu interval yang Anda tentukan. Anda juga harus menentukan waktu interval dengan tepat untuk menghindari masalah ini.
2. Entah bagaimana itu masih terjadi karena alasan apapun, Anda harus memeriksa bendera global bahwa permintaan sebelumnya selesai atau tidak sebelum mengirim permintaan lain. Ini akan melewatkan interval waktu itu tetapi tidak akan mengirim permintaan sebelum waktunya.
Juga jika Anda ingin mengatur nilai ambang bahwa setelah beberapa nilai bagaimanapun polling harus diatur maka Anda dapat melakukannya dengan cara berikut.
Berikut adalah contoh kerja. dijelaskan secara rinci di sini
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; } }]);
sumber