次のコードは、サイレント論理エラーを実行します。
const arr = [];
class Point{
constructor(){
this.x = Math.random() * 1000000;
this.y = Math.random() * 1000000;
}
}
console.time('foo');
let avg = 0;
for(let i = 0; i < 114000000; i++ ){
arr.push(new Point());
avg += arr[i].x / 1000;
}
console.log(avg, arr.length);
// shouldn't this double the avg ?
for(let i = 0; i < 114000000; i++ ){
avg += arr[i].x / 1000;
}
console.log(avg, arr.length);
console.timeEnd('foo');
CodePen- http: //codepen.io/darkyen/pen/yOPMZg?editors=0010
考えられる動作:
avg
2番目のforループの後の変数は2倍にし、配列の長さは1億1,400万にする必要があります。
メモリエラーが発生します。
スクリプトとして実行したときの出力:
avg
2番目のforループの後も変化しません。あなたが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++;
}
これは、CodePen内のフレームコードを調べることで確認できます。
shouldStopLoop
コード内に呼び出しを挿入します。彼ら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には同様の機能があり、ループ保護ライブラリとしてオープンソース化されています-500 LoC未満。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加