2013-02-18 14 views
30

Sto costruendo un'app Web utilizzando AngularJS. L'app deve eseguire il polling di un URL che restituisce i dati JSON e rendere tali dati disponibili per qualsiasi parte dell'app. Da quanto ho letto fino ad ora, la mia migliore scommessa è creare un servizio che gestisca il polling e conservi la propria cache interna dei dati JSON, e quindi iniettare il servizio in qualsiasi parte dell'app che desideri consultare tali dati. Quello su cui mi sono perso è come farlo davvero. L'esempio più vicino che ho trovato è this question, ma sembra che stia creando un servizio che viene chiamato manualmente da un controller specifico (che è esso stesso legato a una determinata route), mentre voglio qualcosa che viene eseguito costantemente sullo sfondo dell'applicazione per sempre indipendentemente da quale parte dell'app è attiva. È fattibile, o sto prendendo l'approccio completamente sbagliato?Servizio di polling HTTP globale di AngularJS

risposta

41

Ecco la mia soluzione:

app.factory('Poller', function($http, $timeout) { 
    var data = { response: {}, calls: 0 }; 
    var poller = function() { 
    $http.get('data.json').then(function(r) { 
     data.response = r.data; 
     data.calls++; 
     $timeout(poller, 1000); 
    });  
    }; 
    poller(); 

    return { 
    data: data 
    }; 
}); 

(chiamate solo a dimostrare che il polling è stato fatto)

http://plnkr.co/edit/iMmhXTYweN4IrRrrpvMq?p=preview

EDIT: Come Josh David Miller ha suggerito nei commenti, dipendenza da questo il servizio deve essere aggiunto nel blocco app.run per garantire che il polling venga eseguito dall'inizio:

app.run(function(Poller) {}); 

E anche spostato la pianificazione del prossimo sondaggio al termine della chiamata precedente. Quindi non ci sarebbe "stacking" di chiamate nel caso in cui il polling si blocca per un lungo periodo.

Plunker aggiornato.

+2

+1 ma vuole qualcosa di correre sempre, in modo da scatenare da un 'app.run' blo ck per assicurarti che funzioni dall'inizio. Vorrei anche controllare la funzione 'poller' per garantire che la precedente chiamata a $ http' completata in modo che non si accumulasse all'infinito, ma sembra che non ci sia modo di farlo con l'implementazione della promessa di AngularJS. –

+1

Thnx. Aggiunti entrambi gli elementi in risposta. E per quanto riguarda lo stacking potrebbe essere evitato spostando semplicemente la pianificazione del prossimo sondaggio in "then" della precedente chiamata. Non è vero? –

+1

Fantastico! :-) Credo di essere stato così concentrato sul metodo originale di 'q' di' isFulfilled() 'che' $ q' non implementa quello che mi è sfuggito del tutto ovvio. lol –

20

Questo è un angular poller service su Github che può essere facilmente inserito nel controller.

Per installare: bower install angular-poller.

Dal momento che si desidera avviare un servizio di polling globale che viene eseguito in background per sempre, si può fare:

// Inject angular poller service. 
var myModule = angular.module('myApp', ['poller']); 

// The home/init controller when you start the app. 
myModule.controller('myController', function($scope, $resource, poller) { 

    // Define your resource object. 
    var myResource = $resource(url[, paramDefaults]); 

    // Create and start poller. 
    var myPoller = poller.get(myResource); 

    // Update view. Most likely you only need to define notifyCallback. 
    myPoller.promise.then(successCallback, errorCallback, notifyCallback); 
}); 

Ora verrà eseguito in background per sempre fino a quando si chiama myPoller.stop() o poller.stopAll().

Se si desidera utilizzare i dati di callback di questo poller in altri controller, si può semplicemente fare:

myModule.controller('anotherController', function($scope, $resource, poller) { 

    /* 
    * You can also move this to a $resource factory and inject it 
    * into the controller so you do not have to define it twice. 
    */ 
    var sameResource = $resource(url[, paramDefaults]); 

    /* 
    * This will not create a new poller for the same resource 
    * since it already exists, but will simply restarts it. 
    */ 
    var samePoller = poller.get(sameResource); 

    samePoller.promise.then(successCallback, errorCallback, notifyCallback); 
}); 
+0

Sembra una grande biblioteca. C'è una app di esempio qualcosa là fuori? – ardochhigh

+0

@ardochhigh Ho intenzione di aggiungere presto un'app campione. Ma prima che ciò accada, puoi controllare la pagina [readme] (https://github.com/emmaguo/angular-poller/blob/master/README.md). :-) –

+0

Grazie a @Emma Guo la pagina README è abbastanza dettagliata. Sono abbastanza nuovo per Angular e sono ancora in difficoltà con alcuni concetti. La tua libreria sembra perfetta per le mie esigenze. Forse cercherò di fare un plunker per una dimostrazione di concetto. Ti farò sapere. – ardochhigh

0

ho biforcato @ codice di fabbrica di ValentynShybanov e ha aggiunto intervalli chiamate (ogni secondo, ogni 5 secondi, ecc), inoltre è possibile arrestare e avviare il poller come si desidera:

http://plnkr.co/edit/EfsttAc4BtWSUiAU2lWf?p=preview

app.factory('Poller', function($http, $timeout) { 
    var pollerData = { 
    response: {}, 
    calls: 0, 
    stop: false 
    }; 

    var isChannelLive = function() { 
    $http.get('data.json').then(function(r) { 
     if (pollerData.calls > 30 && pollerData.stop === false) { // call every minute after the first ~30 secs 
     var d = new Date(); 
     console.log('> 30: ' + d.toLocaleString() + ' - count: ' + pollerData.calls); 
     pollerData.calls++; 
     $timeout(isChannelLive, 10000); 
     } else if (pollerData.calls > 15 && pollerData.calls <= 30 && pollerData.stop === false) { // after the first ~15 secs, then call every 5 secs 
     var d = new Date(); 
     console.log('> 15 & <= 30: ' + d.toLocaleString() + ' - count: ' + pollerData.calls); 
     pollerData.calls++; 
     $timeout(isChannelLive, 5000); 
     } else if (pollerData.calls <= 15 && pollerData.stop === false) { // call every 1 second during the first ~15 seconds 
     var d = new Date(); 
     console.log('<= 15: ' + d.toLocaleString() + ' - count: ' + pollerData.calls); 
     pollerData.calls++; 
     $timeout(isChannelLive, 1000); 
     } 

     pollerData.response = r.data; 
    }); 

    }; 
    var init = function() { 
    if (pollerData.calls === 0) { 
     pollerData.stop = false; 
     isChannelLive(); 
    } 
    }; 
    var stop = function() { 
    pollerData.calls = 0; 
    pollerData.stop = true; 
    }; 

    return { 
    pollerData: pollerData, // this should be private 
    init: init, 
    stop: stop 
    }; 
}); 
Problemi correlati