Feedback con semplicità
Un trucco per mostrare l'avanzamento di task da una pagina web
Quando abbiamo un operazione lunga da svolgere è solitamente una cattiva idea non dare un feedback ad un utente. Questo potrebbe pensare che l'applicazione si sia bloccata, potrebbe rilanciare il comando (aggravando la situazione) o chiudere il browser.
Mostrare l'avanzamento di un task in una applicazione web può essere un compito molto complesso.
Chi programma applicazioni client (con librerie come gtk, qt ecc.) solitamente apre un thread per svolgere il task lungo mentre tramite l'utilizzo di funzioni di callback o tramite un timer viene aggiornata la progressbar e il log.
L'architettura di un applicazione web invece prevede che la gestione di ogni richiesta avvenga in modo indipendente e isolato. Il compito di gestire il ciclo request/response (sequenzialmente, in thread o processi separati) è demandato all'application server. In questo contesto aprire un thread può non essere una buona idea.
Per risolvere questo problema c'è una semplicissima soluzione. Basta dirigere l'output del nostro task lungo su un iframe e fare in modo che dia il risultato delle operazioni mano a mano. Ecco la pagina:
<a id="start_import" href="very_long_task" target="iframe">
Start import
</a>
<div>Log</div>
<iframe name="iframe" width=520 height=200></iframe>
La nostra vista "very_long_task" invece sarà più o meno così (stiamo parlando di Plone in questo caso ma il concetto si può utilizzare anche in altri framework):
response = self.request.RESPONSE
for i in range(100):
response.write("Step number (%s/100)" % (i+1,))
very_long_function()
Per abbellire ulteriormente possiamo utilizzare una progressbar con un po' di javascript per estrarre la percentuale dall'iframe:
jq('#start_import')
.click(function (){
// Progressbar
var pb = jq("#progressbar").progressbar();
var update_progress_bar = function (){
var $iframe = jq(window.frames.iframe.document);
var text = $iframe.find('div:last').text(); // done file xxx (5/10)
var matches = text.match(/[0-9]+\/[0-9]+/); // get "5/10"
var n, perc;
if (matches){
n = matches[0].split('/');
perc = Math.round(parseInt(n[0])/parseInt(n[1]) * 100);
pb.progressbar( "option", "value", perc );
}
};
setInterval(update_progress_bar,500);
});
Questo è il risultato:
Ecco fatto.
re: molti record
Maurizio Lupo
molti record
Bartolomeo