2009-03-23 8 views
50

Possiedo JavaScript che esegue un sacco di calcoli e valori di lettura/scrittura da/verso il DOM. La pagina è enorme quindi spesso questo blocca il browser fino a un minuto (a volte più lungo con IE) con il 100% di utilizzo della CPU.Impedire il javascript a lungo in esecuzione per bloccare il browser

Esistono risorse sull'ottimizzazione di JavaScript per impedire che ciò accada (tutto quello che posso trovare è come disattivare l'avviso di script a lungo termine di Firefox)?

risposta

44

se è possibile trasformare l'algoritmo di calcolo in qualcosa che può essere chiamato in modo iterativo, è possibile rilasciare il controllo del browser a intervalli frequenti utilizzando setTimeout con un valore di timeout breve.

Per esempio, qualcosa di simile ...

function doCalculation() 
{ 
    //do your thing for a short time 

    //figure out how complete you are 
    var percent_complete=.... 

    return percent_complete; 
} 

function pump() 
{ 
    var percent_complete=doCalculation(); 

    //maybe update a progress meter here! 

    //carry on pumping? 
    if (percent_complete<100) 
    { 
     setTimeout(pump, 50); 
    } 
} 

//start the calculation 
pump(); 
+2

Sai se questo funzionerebbe ancora se usi 'setTimeout (pump, 0)'? Oppure questo potrebbe mantenere in anticipo il codice del browser che risponde all'input del mouse, aggiorna il misuratore di avanzamento o altri elementi DOM? – Andy

+0

@Andy Sì, anche "setTimeout" con 0 aiuterà. Vedi alcune delle risposte a [questa domanda] (https://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful). – ShreevatsaR

1

È possibile provare a eseguire calcoli con esecuzione prolungata in thread (vedere JavaScript and Threads), sebbene non siano molto portabili.

Si può anche provare a utilizzare qualche profiler Javascript per individuare i colli di bottiglia delle prestazioni. Firebug supporta la profilatura di javascript.

7

Utilizzare timeout.

Inserendo il contenuto del loop in funzioni separate e chiamandole da setTimeout() con un timeout di 50 o giù di lì, il javascript produrrà il controllo del thread e tornerà un po 'di tempo dopo, consentendo al Interfaccia utente per ottenere un look-in.

C'è un buon lavoro here.

2

avevo bloggato su in-browser performance qualche tempo fa, ma mi permetta di riassumere quelli relativi al DOM per voi qui.

  • Aggiornare il DOM il meno frequentemente possibile. Apporta le tue modifiche agli oggetti DOM in memoria e aggiungili solo una volta al DOM.
  • Utilizzare innerHTML. È più veloce dei metodi DOM nella maggior parte dei browser.
  • Utilizzare la delega dell'evento anziché la normale gestione degli eventi.
  • Conoscere quali chiamate sono costose ed evitarli. Ad esempio, in jQuery, $ ("div.className") sarà più costoso di $ ("# someId").

poi ci sono alcune relative a JavaScript stessa:

  • Loop il meno possibile. Se si dispone di una funzione che raccoglie i nodi DOM e un'altra che li elabora, si esegue il ciclo due volte. Invece, passa una funzione anonima alla funzione che raccoglie i nodi ed elabora i nodi mentre li stai raccogliendo.
  • Utilizzare la funzionalità nativa quando possibile. Ad esempio, per Ogni iteratore.
  • Utilizzare setTimeout per consentire al browser di respirare una volta ogni tanto.
  • Per le funzioni costose dotate di output idempotenti, memorizzare i risultati in cache in modo da non doverli ricalcolare.

C'è altro nel mio blog (link sopra).

1

Questo è ancora un po 'sanguinante, ma Firefox 3.5 ha queste cose chiamate Web Workers, ma non sono sicuro del loro supporto in altri browser.

Mr. Resig ha un articolo su di loro qui: http://ejohn.org/blog/web-workers/

E il Simulated Annealing è probabilmente l'esempio più semplice di esso, se si noterà la Firefox logo filatura non congelare, quando i thread di lavoro stanno facendo le loro richieste (quindi non congelando il browser).

+0

Perché i web worker non sono la risposta qui? –

+0

Beh, ho risposto a questo in 09 'quindi forse non era così ampiamente usato allora ... – leeand00

+0

Buon punto, beh, certamente dovrebbe essere in alto ora. L'utilizzo di setTimeout mi sembra un hackeroso, qualunque cosa tu faccia, a meno che tu non abbia davvero bisogno di un timeout per qualcosa. Se vai su codepen.io su Chrome Windows adesso e fai un algoritmo con la dicitura complessità O (N!) Come trovare tutte le permutazioni della stringa "ABCDEFGHIJKLMNOP", il tuo browser si bloccherà e non risponderà. In un thread di lavoro, l'interfaccia utente continua a funzionare autonomamente. Questa è chiaramente la risposta corretta. –

1

La mia esperienza è che la manipolazione DOM, specialmente in IE, è molto più un problema per le prestazioni rispetto al "core" JavaScript (looping, ecc.).

Se si stanno costruendo nodi, è molto più veloce in IE farlo costruendo una stringa HTML e quindi impostando innerHTML su un contenitore che usando metodi DOM come createElement/appendChild.

0

Si potrebbe provare a ridurre il codice da

$(xmlDoc).find("Object").each(function(arg1) { 
    (function(arg1_received) { 
       setTimeout(function(arg1_received_reached) { 

        //your stuff with the arg1_received_reached goes here 

       }(arg1_received), 0) 
      })(arg1) 
}(this)); 

o per "per" loop provare

for (var i = 0 ; i < 10000 ; i = i + 1) { 
    (function(arg1_received) { 
     setTimeout(function(arg1_received_reached) { 

      //your stuff with the arg1_received_reached goes here 

     }(arg1_received), 0) 
    })(arg1_to_send) 
} 

ho avuto lo stesso problema e miei clienti è stato segnalato questo come errore di "Kill pagina". Ma ora ho una soluzione migliore per questo. :)

Problemi correlati