2011-10-26 15 views
9

Vorrei inserire del codice Javascript mentre sia il processo principale che il thread sono liberi di aggiornare l'interfaccia utente del browser.È possibile "thread" Javascript e mantenere l'accesso all'interfaccia utente?

Ad esempio:

function StartStuff() { 
    StartThreadedCode(); 
    // do more work and update the UI while StartThreadedCode() does its work 
} 

function StartThreadedCode() { 
    // do stuff (do work and update the UI) 
} 

E 'possibile?

+1

hai dato un'occhiata ai webworker? https://developer.mozilla.org/en/Using_web_workers – Mic

risposta

16

Ci sono due modi principali per ottenere "multithreading" in Javascript. Il primo è una soluzione cross-browser, che funzionerebbe anche con i browser più vecchi, ma è più complicata da implementare.

L'idea alla base di questo è che si concede all'interfaccia utente un po 'di tempo per aggiornarsi di tanto in tanto. Poiché non c'è alcuna funzione di sospensione sincrona in Javascript, l'unico modo per ottenere ciò è utilizzare setTimeout (o setInterval con logica un po 'più complicata) per ritardare l'esecuzione di ogni ciclo dei calcoli complessi. Ciò darebbe al browser un po 'di tempo per aggiornare l'interfaccia utente tra i loop, dando l'effetto visivo di più cose che accadono simultaneamente. Alcuni ms dovrebbero essere più che sufficienti per l'interfaccia utente per riflettere le ultime modifiche.

Ha i suoi svantaggi, ovviamente, e può essere piuttosto difficile da implementare se ci sono più azioni che l'utente potrebbe voler fare mentre vengono eseguiti i calcoli in background. Inoltre, può rallentare drasticamente l'intero calcolo dello sfondo, poiché di tanto in tanto viene ritardato di alcuni ms. In casi specifici, tuttavia, fa il trucco e si comporta bene.

La seconda opzione sarebbe quella di utilizzare i web worker, che sono fondamentalmente script Javascript che funzionano indipendentemente in background, come una discussione. È molto più semplice da implementare, devi solo preoccuparti della messaggistica tra il codice principale e gli operatori in background, quindi l'intera applicazione non ne risente tanto. Puoi leggere di usarli dal link postato da Mic https://developer.mozilla.org/en/Using_web_workers. Il più grande svantaggio dei web worker è il loro supporto da parte dei browser, che puoi vedere su http://caniuse.com/#search=worker Non c'è soluzione alternativa per IE < 9 o browser per dispositivi mobili che simulano veramente l'effetto, quindi non c'è molto che tu possa fare per quei browser, ma poi di nuovo, i vantaggi dei browser moderni potrebbero superare il supporto di IE. Questo, ovviamente, dipende dalla tua applicazione.

Modifica: Non sono sicuro se ho spiegato chiaramente il primo concetto, quindi ho deciso di aggiungere un piccolo esempio. Il codice seguente è funzionalmente equivalente a:

for (var counter = 0; counter < 10; counter++) { 
    console.log(counter); 
} 

Ma invece di accesso 0-9 in rapida successione, ritarda 1s prima di eseguire la successiva iterazione del ciclo.

var counter = 0; 

// A single iteration of your calculation function 
// log the current value of counter as an example 
// then wait before doing the next iteration 
function printCounter() { 
    console.log(counter); 
    counter++; 
    if (counter < 10) 
    setTimeout(printCounter, 1000); 
} 

// Start the loop 
printCounter(); 
1

A partire dal 2009 (FF 3.5/Gecko 1.9.1) una nuova API Web è stato aggiunto che si chiama Web Workers. Funziona anche su Chrome 4+, Opera 10.6+ e IE10 +.

Il worker è fondamentalmente un thread in background eseguito in un processo separato.

La comunicazione tra il processo principale (ad esempio il thread principale dell'interfaccia utente) e il processo slave (il thread in background, il worker) viene stabilita con l'ausilio di una funzione PostMessage/onmessage generica in cui è possibile scambiare qualsiasi dato desiderato tra le due parti.

Vale la pena ricordare che ogni singolo lavoratore è assegnato a un nucleo diverso. Ad esempio, creando 4 diversi worker (che eseguono un calcolo a lungo termine) su un quad-processore, vedrai tutti i 4 core della CPU come 100% mentre lo script principale è ancora inattivo e quindi rispondendo agli eventi dell'interfaccia utente (guarda this example).

un esempio di base:

principali-script.js

if ("function" !== typeof window.Worker) { 
    throw "Your browser doesn't support Web Workers"; 
} 
var thread = new Worker("background-thread.js"); 
thread.onmessage = function(e) { 
    console.log("[A] : I received a " + e.data + " :-P"); 
}; 
thread.onerror = function(e) { 
    console.log(e); 
}; 

console.log("[A] : I'm sending a PING :-)"); 
thread.postMessage("PING"); 

sfondo-thread.js

onmessage = function(e) { 
    console.log("[B] : I receveid a " + e.data + " :-)"); 
    console.log("[B] : I will respond with a PONG ;-)"); 
    postMessage("PONG"); 
}; 

L'esempio riportato sopra dovrebbe produrre il seguente output a vostra console del browser:

[A]: Sto inviando un PING :-)

[B]: Ho receveid un PING :-)

[B]: Risponderò con un PONG ;-)

[a]: ho ricevuto una PONG :-P

Così felice PING-zione allo script di fondo!

Problemi correlati