Quando si scrive il codice in Codepen - che in realtà non lo esegue così com'è, ma piuttosto prima si applicano alcune trasformazioni ad esso.
Lo analizzano in un abstract syntax tree, i loop di ricerca e insert instructions explicitly interrompono l'esecuzione del ciclo se è trascorso troppo tempo.
Quando si esegue:
for(let i = 0; i < 114000000; i++){
arr.push(new Point());
avg += arr[i].x/1000;
}
Il codice viene eseguito come:
for (var i = 0; i < 114000000; i++) {
if (window.CP.shouldStopExecution(1)) { // <- injected by Codepen!!!
break;
}
arr.push(new Point());
avg += arr[i].x/1000;
iter++;
}
È possibile vedere questo ispezionando il codice telaio interno CodePen stessa.
Si iniettano chiamate shouldStopLoop
all'interno del codice. Hanno uno script chiamato stopExecutionOnTimeout
che fa qualcosa di simile (fonte da Codepen):
var PenTimer {
programNoLongerBeingMonitored:false,
timeOfFirstCallToShouldStopLoop:0, // measure time
_loopExits:{}, // keep track of leaving loops
_loopTimers:{}, // time loops
START_MONITORING_AFTER:2e3, // give the script some time to bootstrap
STOP_ALL_MONITORING_TIMEOUT:5e3, // don't monitor after some time
MAX_TIME_IN_LOOP_WO_EXIT:2200, // kill loops over 2200 ms
exitedLoop:function(o) { // we exited a loop
this._loopExits[o] = false; // mark
},
shouldStopLoop:function(o) { // the important one, called in loops
if(this.programKilledSoStopMonitoring) return false; // already done
if(this.programNoLongerBeingMonitored)return true;
if(this._loopExits[o]) return false;
var t=this._getTime(); // get current time
if(this.timeOfFirstCallToShouldStopLoop === false)
this.timeOfFirstCallToShouldStopLoop = t;
return false;
}
var i= t - this.timeOfFirstCallToShouldStopLoop; // check time passed
if(i<this.START_MONITORING_AFTER) return false; // still good
if(i>this.STOP_ALL_MONITORING_TIMEOUT){
this.programNoLongerBeingMonitored = true;
return false;
}
try{
this._checkOnInfiniteLoop(o,t);
} catch(n) {
this._sendErrorMessageToEditor(); // send error about loop
this.programKilledSoStopMonitoring=false;
return true; // killed
}
return false; // no need
},
_sendErrorMessageToEditor:function(){/*... */
throw "We found an infinite loop in your Pen. We've stopped the Pen from running. Please correct it or contact [email protected]";
};
Se si desidera eseguire da soli - JSBin ha funzionalità simili e hanno open sourced it come libreria di loop di protezione - sotto 500 Loc.
fonte
2016-04-05 12:52:12
Una piccola nota: il cambio "avg" è dovuto alla precisione dei numeri in virgola mobile. Ad un certo punto, il valore di 'avg' diventa così grande che aggiungere un numero piccolo ad esso non ha alcun effetto, a causa della dimensione del bit della mantissa. –
potrebbe essere un problema con 'i <114000000'? [codepen senza array] (http://codepen.io/vpArth/pen/eZeGGr) –
@AndersTornblad 'Math.random() * 1000000/1000' dovrebbe essere in mezzo casi più di 500, che non è sicuramente sufficiente per essere ingoiato da errori di arrotondamento/precisione per un numero così piccolo come '1261167461.290721' (per la mia esecuzione corrente) – zerkms