我有一個循環需要在瀏覽器中運行2億次。這是一個模擬器,有幾個人需要定期使用。大約需要15分鐘才能運行,但在此期間,瀏覽器會頻繁彈出警告,提示「此腳本耗時過長」等,並且在該功能期間它完全掛起Firefox。這也意味着該頁面不會更新我的狀態指示器(這只是一個數字)。阻止JavaScript在大循環上鎖定瀏覽器
我用Google搜索「的JavaScript產量」和讀取的第一個4頁命中。一些討論一個新的「yield」關鍵字,但是隻有一個描述和例子,我覺得這是不可理解的,例如, 「包含yield關鍵字的函數是一個生成器,當你調用它時,它的形式參數綁定到實際參數,但它的實體並沒有被實際評估」。 yield
屈服於用戶界面嗎?
爲數不多的解決方案,我也發現這是舊的文章,它使用過時的被叫參數和定時器,稱自己: http://www.julienlecomte.net/blog/2007/10/28/
然而,上面的例子中不包含任何循環變量或狀態,當我加上它們就會崩潰,而我的淨結果總是爲零。
它也沒有做分塊,但我已經發現了一些其他的例子,其使用「索引%100 == 0」每次迭代塊。但是,這似乎是一個緩慢的做法。例如。這樣的:
How to stop intense Javascript loop from freezing the browser
但它沒有任何的方式來更新進度,不屈服的UI(所以仍然掛起瀏覽器)。這裏是一個執行過程中掛起的瀏覽器測試版:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
var spins = 1000000
var chunkSize = 1000;
var chunk;
function Stats() {this.a=0};
var stats = new Stats();
var big;
var index = 0;
var process = function() {
for (; index < spins; index++) {
stats.a++;
big = (big/3.6)+ big * 1.3 * big/2.1;
console.write(big);
// Perform xml processing
if (index + 1 < spins && index % 100 == 0) {
document.getElementById("result").innerHTML = stats.a;
setTimeout(process, 5);
}
}
document.getElementById("result").innerHTML = stats.a;
};
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="process()">
<div id=result>result goes here.</div>
</body>
</html>
,這裏是另一種嘗試,其中stats.a
始終爲零(所以我相信有一些範圍界定問題):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
var spins = 1000000
var chunkSize = 1000;
var chunk;
function Stats() {this.a=0};
var stats = new Stats();
function doIt() {
function spin() {
for (spinIx=0; (spinIx<chunkSize) && (spinIx+chunk < spins); spinIx++) {
stats.a++;
}
}
for (chunk =0; chunk < spins; chunk+=chunkSize){
setTimeout(spin, 5);
document.getElementById("result").innerHTML = stats.a;
}
document.getElementById("result").innerHTML = stats.a;
}
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="doIt()">
<div id=result>result goes here.</div>
</body>
</html>
我我花了48小時試圖讓這項工作 - 無論我是非常愚蠢的,或者這是非常困難的。有任何想法嗎?
有人建議網絡工作者。我試了好幾天纔得到他的工作,但我找不到一個類似的例子,通過一個數字等。下面的代碼是我最後一次嘗試使它工作,但結果始終爲0,當它應該是100000。它失敗了,就像我上面的第二個例子失敗一樣。
spinMaster.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<script>
if(typeof(Worker)==="undefined") {
document.write("<h1>sorry, your browser doesnt support web workers, please use firefox, opera, chorme or safari</h1>");
}
var worker =new Worker("spinWorker.js");
worker.postMessage({times:1000000});
worker.onmessage=function(event){
document.getElementById("result").innerHTML=event.data;
};
</script>
<div id="result">result goes here</div>
</body>
</html>
spinWorker.js
function State() {
this.a=0;
}
var state = new State();
self.addEventListener('message', spin, false);
function spin(e) {
var times, i;
times = e.data.times;
//times = 1000000; // this doesnt work either.
for(i;i<times;i++) {
state.a++;
}
self.postMessage(state.a);
}
結果輸出:0
因爲JS通常是單線程的,我不認爲有任何解決方法。但是,如果您只支持較新的瀏覽器,則可能需要查看網絡工作人員,這可能會產生一個新線程來完成工作:https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers – kennypu
@kennypu您應該將其作爲答案發布。 –
你的性能問題很可能是常量DOM操作(每5ms),這是非常昂貴的。嘗試以不同的速率更新DOM,例如每10-20秒鐘查看一次,看看它是否會使其性能更好/更快。 – elclanrs