Esegui attività in background in Javascript

Ho un compito intensivo di cpu che devo eseguire sul client. Idealmente, mi piacerebbe essere in grado di invocare la funzione e triggersre eventi di progresso utilizzando jquery in modo da poter aggiornare l’interfaccia utente.

So che javascript non supporta il threading, ma ho visto alcuni articoli promettenti che cercano di imitare il threading usando setTimeout.

Qual è l’approccio migliore da usare per questo? Grazie.

Ho avuto un problema simile a risolvere recentemente dove avevo bisogno di mantenere il mio thread dell’interfaccia utente mentre crunching alcuni dati da visualizzare.

Ho scritto una libreria Background.js per gestire alcuni scenari: una coda di sfondo sequenziale (basata sulla libreria WorkerQueue), un elenco di lavori in cui ognuno è chiamato su ogni timer e un iteratore di array per aiutare a suddividere il lavoro in blocchi più piccoli . Esempi e codice qui: https://github.com/kmalakoff/background

Godere!

Fondamentalmente, quello che vuoi fare è dividere l’operazione in pezzi. Pertanto, supponiamo di avere 10.000 articoli da elaborare, di memorizzarli in un elenco e di elaborarli con un piccolo ritardo tra ogni chiamata. Ecco una struttura semplice che potresti usare:

function performTask(items, numToProcess, processItem) { var pos = 0; // This is run once for every numToProcess items. function iteration() { // Calculate last position. var j = Math.min(pos + numToProcess, items.length); // Start at current position and loop to last position. for (var i = pos; i < j; i++) { processItem(items, i); } // Increment current position. pos += numToProcess; // Only continue if there are more items to process. if (pos < items.length) setTimeout(iteration, 10); // Wait 10 ms to let the UI update. } iteration(); } performTask( // A set of items. ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'], // Process two items every iteration. 2, // Function that will do stuff to the items. Called once for every item. Gets // the array with items and the index of the current item (to prevent copying // values around which is unnecessary.) function (items, index) { // Do stuff with items[index] // This could also be inline in iteration for better performance. }); 

Tieni inoltre presente che Google Gears supporta il lavoro su un thread separato . Firefox 3.5 ha anche introdotto i propri dipendenti che fanno la stessa cosa (sebbene seguano lo standard W3 , mentre Google Gears utilizza i propri metodi).

Se è ansible applicare il browser per essere utilizzato, o altrimenti si sa già che si tratta di una nuova versione di Firefox, è ansible utilizzare i nuovi WebWorker da Mozilla. Ti permette di generare nuovi thread.

A seconda di quali sono i tuoi requisiti, puoi facilmente iniziare a utilizzare Gears. Gears supporta i thread, che potrebbero fare ciò che vuoi.

Come hai detto, setTimeout è l’altra opzione. A seconda del tipo di attività, è ansible distribuire ogni iterazione di un ciclo a una chiamata setTimeout separata con qualche spaziatura intermedia, oppure potrebbe essere necessario separare parti dell’algoritmo principale in funzioni separate che possono essere chiamate una ad una in nello stesso modo in cui chiamereste ogni iterazione.

Ottima risposta Kevin! Ho scritto qualcosa di simile qualche anno fa, anche se meno sofisticato. Il codice sorgente è qui se qualcuno lo desidera:

http://www.leapbeyond.com/ric/jsUtils/TaskQueue.js

Qualunque cosa con un metodo run() può essere accodata come un’attività. Le attività possono eseguire nuovamente la coda per eseguire il lavoro in blocchi. Puoi dare priorità alle attività, aggiungerle / rimuoverle a piacimento, mettere in pausa / riprendere l’intera coda, ecc. Funziona bene con operazioni asincrone – il mio uso originale per questo era di gestire più richieste simultanee di XMLHttp.

L’utilizzo di base è piuttosto semplice:

 var taskQueue = new TaskQueue(); taskQueue.schedule("alert('hello there')"); 

I commenti di intestazione nel file .js forniscono esempi più avanzati.

Ecco la mia soluzione al problema, nel caso qualcuno volesse un semplice pezzo di codice copia-incollabile:

  var iterate = function (from, to, action, complete) { var i = from; var impl = function () { action(i); i++; if (i < to) setTimeout(impl, 1); else complete(); }; impl(); }; 

La mia raccomandazione più forte è quella di visualizzare un semplice caricamento.gif durante l’operazione. L’utente accetta spesso una certa durata se è stato “detto” che potrebbe richiedere del tempo.

Ajaxload – Ajax che carica il generatore di gif

Questo è un esempio molto semplice di come creare thread in JavaScript. Nota che spetta a te interrompere le tue funzioni di thread (istruzione di sospensione). Se lo desideri, puoi utilizzare un setTimeout anziché il mio ciclo while per eseguire periodicamente lo scheduler. Nota anche che questo esempio funziona solo con JavaScript versione 1.7+ (firefox 3+) puoi provarlo qui: http://jslibs.googlecode.com/svn/trunk/jseval.html

 //// thread definition function Thread( name ) { for ( var i = 0; i < 5; i++ ) { Print(i+' ('+name+')'); yield; } } //// thread management var threads = []; // thread creation threads.push( new Thread('foo') ); threads.push( new Thread('bar') ); // scheduler while (threads.length) { var thread = threads.shift(); try { thread.next(); threads.push(thread); } catch(ex if ex instanceof StopIteration) { } } 

L'output è:

 0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar) 

Sembra che questo problema sia stato risolto nel nodo stesso.
richiede child_process che è incluso in nodejs 0.10.4