Ответ 1
Когда вы пишете код в Codepen - они фактически не выполняют его как есть, а скорее применяют к нему некоторые преобразования.
Они анализируют его в абстрактное синтаксическое дерево, находят циклы и вставляют инструкции явно, чтобы прекратить выполнение цикл, если прошло слишком много времени.
Когда вы выполните:
for(let i = 0; i < 114000000; i++ ){
arr.push(new Point());
avg += arr[i].x / 1000;
}
Ваш код работает как:
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++;
}
Вы можете увидеть это, проверив код кадра внутри самого кода.
Они вводят shouldStopLoop
вызовы внутри вашего кода.
У них есть script, называемый stopExecutionOnTimeout
, который делает что-то вроде этого (источник от 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]";
};
Если вы хотите запустить его самостоятельно - у JSBin есть аналогичная функциональность, и они открывают sourced it в качестве библиотеки защиты от цикла - до 500 LoC.