Ostatnio, w jednym z projektów, musiałem wykonywać pewne zapytanie http co X sekund. Normalnie pewnie wszystko bym opakował w plugin jQuery (albo wykorzystał istniejący) i wykonywał polecenie ajax co jakiś czas.
Niestety, albo i stety, projekt oparłem na Angular a API dostępowe zrobiłem na bazie promise. Ze względu na to, że polling miał być wykonywany tylko w kilku miejscach, nie było sensu wsadzać tego do API, jak i pisać za każdym razem ręcznie polling dla konkretnej metody/strony.
Dlatego też stworzyłem coś takiego:
var app = angular.module('poller-wrapper', []);
app.factory('poller', [
'$timeout', '$q',
function ($timeout, $q) {
var tasks = [];
function Task(opts) {
this.opts = opts;
}
Task.prototype = {
start: function () {
var deferred = $q.defer(),
self = this;
(function tick() {
var p = self.opts.action.call(null, self.opts.params),
rejected = false;
p.then(function (data) {
deferred.notify(data.data);
}, function () {
rejected = true;
deferred.reject('Error occured');
});
self.timeoutId = $timeout(tick, self.opts.intevral);
})();
this.promise = deferred.promise;
return this;
},
stop: function () {
$timeout.cancel(this.timeoutId);
this.timeoutId = null;
}
};
function create(opts) {
var task = new Task(opts);
tasks.push(task);
return task;
}
function stopAll() {
var i = 0; len = tasks.length;
for (; i < len; i++) {
tasks[i].stop();
}
}
function clear() {
stopAll();
tasks = [];
}
return {
create: create,
stopAll: stopAll,
clear: clear
};
}
]);
Wykorzystanie jest dość proste, zakładamy tylko, że metoda którą będziemy wykonywać cyklicznie zwraca zmodyfikowany promise przez usługę $http:
var app = angular.module('some-app', ['poller-wrapper']);
app.provider('api', function () {
var baseUri = 'http://localhost';
this.baseUri = function (uri) {
baseUri = uri || baseUri;
};
function buildUri(uri) {
return baseUri + uri;
}
this.$get = [
'$http',
function ($http) {
return {
action: function () {
return $http.get(buildUri('/action'));
}
};
}
];
});
app.controller('NameCtrl', [
'$http', 'poller', 'api',
function ($http, poller, api) {
var poll = poller.create({
intevral: 1000,
action: api.action
});
poll.start();
poll.promise.then(/*resolve*/ null,/*reject*/ null, /*notify*/ function () {
$scope.data = data;
});
poll.promise.catch((/*reject*/ function () {
alert('error');
});
$scope.stop = function () {
poll.stop();
};
}
]);
Co o tym sądzicie? Ma to ręce i nogi? Może da się to lepiej napisać? U mnie to śmiga, może powinienem jeszcze gdzieś testy tego wrzucić, ale to chyba będzie już inny post ;)














