同事報案,用JS Bin跑迴圈計算從1加到n測試效能,發現 for 迴圈次數增加到100萬後加總結果不對,每次執行會得到小於正確值(499999500000)的隨機數字;但若不用for改用lodash _.times(),跑再多次結果也是正確的。
為了調查,先將程式碼簡化到可重現問題的最精簡內容:
var count = 1000000;
var sum = 0;
for (var i=0;i<count;i++)
sum += i;
console.log("Inline:"+sum);
發現一個現象,如果用<script>將程式內嵌進HTML,執行結果正確;要移到JavaScript區塊才會出錯,如下例:
Inline測試結果為499999500000,而JavaScript測試結果為每次不同的亂數,然後我還注意到下方有段警告:
Exiting ptoential infinite loop. To disable protection: add "// noprotect" to your code.
JS Bin說它「已跳出潛在無窮迴圈」!
研判這是JS Bin防止程式碼陷入無窮迴圈的機制,當迴圈連續執行超過一定次數就強行中止(聽起來頗神奇,不知是怎麼做到的),但後面的程式碼會繼續執行。中斷時機不一可以解釋為什麼每次跑出的數字不同,而_.times()的演算法不符合潛在無窮迴圈的標準,故未受影響。
要避免保護機制影響執行結果,在程式碼開頭加入// noprotect關掉保護,搞定收工!