Bookmark and Share

Feedback con semplicità

Un trucco per mostrare l'avanzamento di task da una pagina web

by Maurizio Lupo - 2010-09-06
Contributors: Davide Moro

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.


molti record

Posted by El Barto at 2010-10-03 18:06
ma se io avessi un CSV da fa caricare all'utente su un'applicazione custom python diciamo ogni mattina con circa 6/7000 righe e circa 50 colonne (trattasi di export da db sql) e browser IE7 posso con questa operazione evitare il time out del browser? Dato che impiega circa 50 minuti a completare l'operazione... e posso dare all'utente la possibilitá di vedere a che punto é l'upload? Ad es. Il numero di riga? Grazie seguiró la risposta online.
Bartolomeo

re: molti record

Posted by Maurizio Lupo at 2010-10-04 08:39
Io sto usando questa tecnica proprio per la stessa attività. La mia importazione dura circa 7/8 minuti e non ho problemi. Lo script funziona con IE7 e per dare info all'utente basta farle scrivere nell'Iframe.

Maurizio Lupo