When you write code in Codepen - they actually don't execute it as-is but rather first apply some transformations to it.
They parse it into an abstract syntax tree, find loops and insert instructions explicitly to stop executing the loop if too much time has passed.
When you do:
for(let i = 0; i < 114000000; i++ ){
arr.push(new Point());
avg += arr[i].x / 1000;
}
Your code runs as:
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++;
}
You can see this by inspecting the frame code inside CodePen itself.
They inject shouldStopLoop calls inside your code.
They have a script called stopExecutionOnTimeout which does something like this (source from 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].";
};
If you want to run it yourself - JSBin has similar functionality and they have open sourced it as the loop-protect library - under 500 LoC.
avgnot changing is due to the precision of floating point numbers. At some point, the value ofavggets so large that adding a small number to it has no effect, because of the bit size of the mantissa.i<114000000? codepen without any arraysMath.random() * 1000000 / 1000should be in half cases more than 500, which is definitely not enough to be swallowed by rounding errors/precision for such a small number as1261167461.290721(for my current run).push()fails), there will be noarr[i]to fetch the.xproperty from, which is more likely the reason foravgnot growing. If all calls to.push()had succeeded,avgwould still be off because of float errors. But I still don't know whyavgis unchanged after the second loop.