Ho un ciclo che deve essere eseguito 200 milioni di volte in un browser. È un simulatore che molte persone devono usare regolarmente. Ci vogliono circa 15 minuti per funzionare, ma durante questo periodo, i browser visualizzeranno frequentemente un avviso con "questo script sta richiedendo troppo tempo" ecc., E blocca completamente Firefox durante la funzione. Ciò significa anche che la pagina non aggiorna il mio indicatore di stato (che è solo un numero).Impedisci a JavaScript di bloccare il browser sul grande loop
Ho cercato su google "javascript yield" e ho letto le prime 4 pagine di risultati. Alcuni discutono una nuova parola chiave "rendimento", ma c'è solo una descrizione ed un esempio, che trovo incomprensibile, ad es. "La funzione che contiene la parola chiave yield è un generatore: quando lo chiami, i parametri formali sono legati ad argomenti reali, ma il suo corpo non viene valutato". yield
cede all'interfaccia utente?
Una delle poche soluzioni che ho trovato è questo vecchio post, che utilizza l'argomento callee deprecato e un timer di chiamarsi: http://www.julienlecomte.net/blog/2007/10/28/
Tuttavia, l'esempio di cui sopra non contiene alcuna variabile loop o di stato, e quando aggiungo questi cade a pezzi e il mio risultato netto è sempre zero.
Inoltre non esegue il chunking, ma ho trovato alcuni altri esempi che utilizzano "indice% 100 == 0" su ogni iterazione. Tuttavia, questo sembra essere un modo lento di farlo. Per esempio. questo:
How to stop intense Javascript loop from freezing the browser
Ma non ha alcun modo per aggiornare i progressi, e non cede alla UI (così si blocca ancora il browser). Ecco una versione di prova che pende il browser durante l'esecuzione:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
var spins = 1000000
var chunkSize = 1000;
var chunk;
function Stats() {this.a=0};
var stats = new Stats();
var big;
var index = 0;
var process = function() {
for (; index < spins; index++) {
stats.a++;
big = (big/3.6)+ big * 1.3 * big/2.1;
console.write(big);
// Perform xml processing
if (index + 1 < spins && index % 100 == 0) {
document.getElementById("result").innerHTML = stats.a;
setTimeout(process, 5);
}
}
document.getElementById("result").innerHTML = stats.a;
};
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="process()">
<div id=result>result goes here.</div>
</body>
</html>
e qui è un altro tentativo che il stats.a
è sempre zero (quindi presumo ci sia qualche problema di scoping):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
var spins = 1000000
var chunkSize = 1000;
var chunk;
function Stats() {this.a=0};
var stats = new Stats();
function doIt() {
function spin() {
for (spinIx=0; (spinIx<chunkSize) && (spinIx+chunk < spins); spinIx++) {
stats.a++;
}
}
for (chunk =0; chunk < spins; chunk+=chunkSize){
setTimeout(spin, 5);
document.getElementById("result").innerHTML = stats.a;
}
document.getElementById("result").innerHTML = stats.a;
}
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="doIt()">
<div id=result>result goes here.</div>
</body>
</html>
I' Ho passato 48 ore cercando di farlo funzionare - o sono molto stupido o questo è molto difficile. Qualche idea?
Diverse persone hanno suggerito i web worker. Ho provato diversi giorni a farlo funzionare, ma non sono riuscito a trovare un esempio simile che superi un numero ecc. Il codice seguente era il mio ultimo tentativo di farlo funzionare, ma il risultato è sempre 0 quando dovrebbe essere 100000. I. fallisce nello stesso modo in cui il mio secondo esempio sopra fallisce.
spinMaster.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<script>
if(typeof(Worker)==="undefined") {
document.write("<h1>sorry, your browser doesnt support web workers, please use firefox, opera, chorme or safari</h1>");
}
var worker =new Worker("spinWorker.js");
worker.postMessage({times:1000000});
worker.onmessage=function(event){
document.getElementById("result").innerHTML=event.data;
};
</script>
<div id="result">result goes here</div>
</body>
</html>
spinWorker.js
function State() {
this.a=0;
}
var state = new State();
self.addEventListener('message', spin, false);
function spin(e) {
var times, i;
times = e.data.times;
//times = 1000000; // this doesnt work either.
for(i;i<times;i++) {
state.a++;
}
self.postMessage(state.a);
}
uscita risultante: 0
dal JS è a thread singolo di solito, non credo che ci sia alcun modo intorno ad esso. Se stai supportando solo i browser più recenti, tuttavia, potresti voler esaminare i web worker, che possono generare una nuova discussione per lavorare: https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers – kennypu
@kennypu Dovresti postarlo come risposta. –
Il tuo problema di prestazioni potrebbe benissimo essere la costante manipolazione DOM (ogni 5 ms), che è MOLTO costoso. Prova ad aggiornare il DOM con una frequenza diversa, diciamo ogni 10-20 secondi e verifica se ciò lo rende migliore o più veloce. – elclanrs