我有一些过程密集的Javascript代码,它触发了“无响应脚本”警告。每个编码步骤必须按照它们被编码的顺序发生。我想我找到了有问题的功能,但我不明白如何在不触发警告的情况下使其工作。
我发现了一些可能对此有帮助的迹象(setTimeout) Javascript: Unresponsive script error 但这真的很模糊,所以我一直在寻找。这是一个更好的例子,但我无法在我的代码中看到实现这个的方法.. How can I give control back (briefly) to the browser during intensive JavaScript processing? 原文 http://www.julienlecomte.net/blog/2007/10/28/ 无论如何都是天才,但我似乎无法在这里实现它。
以下是我认为导致合适的代码。
// -----------------------------------
// Output stats for all nations
// by continent in a colon delimited
// list further delimited by a ~
// ( ContinentName:NationPower:NationHTML )
// expects the output from the
// continent_stats function
// -----------------------------------
function Nations(ContinentData) {
document.write("<tr><th>Nation Stats</th></tr><tr>"); // setup progress bar
var NationString = ""; // init the string
var Carray = ContinentData.split("*"); //continents
for (cit = 0; cit < Carray.length; cit++) { // go through the continents
var Cstat = Carray[cit].split(":"); // make an array of the individual continent stats
var NumberOfNations = Cstat[4]; // nation #
var ContinentName1 = Cstat[0]; // Continent Name
document.write("<td class='ProgressBarText'>" + ContinentName1 + "</td><td class='ProgressBars'>"); // Format loader screen text
for (nnum = 0; nnum < NumberOfNations; nnum++) { // go through the number of nations on the continent
var nat1 = BuildCulture(); // build the nation
var Natname= "Nation"+padLeft(nnum,2,"0"); // name the nation
NationString = NationString + ContinentName1 + ":" + Natname + ":" + nat1 + "~"; // build the string
document.write("█"); // add to progress bar
}
document.write("</td><td>"+NumberOfNations+ " Nations</td></tr>"); // progress bar complete
}
document.write("</table>"); // end the loader screen table
// send the nation string back
return NationString;
}
所以你可以看到它在各大洲之间循环并为每个大陆创造了国家。 BuildCulture()函数是罪魁祸首。它本身就可以很好地工作,但是在大约4个大陆的过程中,8或9串在一起,并且警告响起。
我尝试过使用
setTimeout( function() { BuildCulture(); }, 1000);
遍布整个地方,在主代码部分,在BuildCulture()函数的开头和结尾,在进入和退出循环的Nations(ContinentData)函数中。它永远不会奏效。
我显然循环太多但我需要每个循环。 SetTimeout会帮助我,还是我在追逐错误的陈述?
如果SetTimeout是我的解决方案的目标,我该如何在此代码中实现它?
非常感谢。
P.S。 我的目标只是在Firefox中工作,因此不需要与IE核心浏览器兼容。
答案 0 :(得分:0)
首先,浏览器是单线程应用程序。所有事件,计时器和交互都是线性的,一步一步完成的。因此,您无法生成新线程或进行并行计算。
从这个意义上说,如果你可以剪切function Nations
并在setTimeout中调用它来提供前一个结果,那么setTimeout可以假设有用。但这不是最佳的;)
其次,请勿触摸DOM !!!
JS可能很快,但触摸DOM(getElements,document.write,innerHTML ......)是 SLOW !
在你的情况下,重写function Nations(ContinentData)
输出一个你将innerHTML的字符串输出到某个dom元素。
重点是所有的计算和准备都将在(相对)快速的JS引擎中完成,结果将被应用或者内部HTML编译为非常慢的DOM。
或者您可以使用DOM对象使用createElem和addChild。无所谓。两种方式都有优点和缺点,但两者都做同样的事情。
第三:尝试网络工作者。他们在模拟'线程'方面做得很好:
http://ejohn.org/blog/web-workers/
http://www.sitepoint.com/javascript-threading-html5-web-workers/
http://www.w3schools.com/html5/html5_webworkers.asp
答案 1 :(得分:0)
好的,因为我无法在任何地方运行,可能会出现一些错误 - 但如果您需要使用超时,这就是您想要的模式。
然而,考虑到结构和你的代码风格,我得到的印象是你可能会以错误的方式解决这个问题。
例如,您的数据来自哪里?为什么结构化数据用字符串表示?你在客户端进行所有这些计算吗?这是游戏吗?什么是buildCulture()
这样做需要这么长时间?无论如何,你应该研究JSON和异步加载(也就是AJAX)。
function Nation(continentData, renderNationComplete) {
// begin our table
var str = '<table>',
continents = continentData.split('*');
// use the `+=` operator to add string together
str += '<tr><th>Nation Stats</th></tr><tr>';
// This will act like a `for` loop -
// the difference is that we can control the iterations
var continentsCount = 0;
function renderContinents(){
if(continentsCount < continents.length) {
var stats = continent[continentsCount].split(':'),
nNations = stats[4],
cName = stats[0];
str += '<td class="ProgressBarText">' + cName + '</td><td class="ProgressBars">';
var nationCount = 0;
function renderNation(){
if(nationCount < nNations) {
var culture = BuildCulture(),
nName = "Nation" + padLeft(nationCount, 2, "0");
str += cName + ':' + nName + ':' + culture + '~';
str += '█'; // not precisely sure what this is for.
nationCount++;
// renderContinents won't proceed till we're done with all the
// renderNations for this particular continent.
setTimeout(function(){ renderNation(); }, 1000);
} else {
// close up the rows
str += '</td><td>' + nNations + ' Nations</td></tr>';
nationCount++;
// this timeout may not be necessary, you'll have to tweak the value.
setTimeout(function(){ renderContinents(); }, 1000);
}
} renderNation();
} else {
str += '</table>';
// everything is done, send it back.
// note: this function does not return anything,
// instead, it keeps on running asynchronously till
// it's done, at which point it call the callback
// that you pass in when it is instantiated.
renderNationComplete(str);
}
} renderContinents();
}
// here we call the Nation function, and pass in another function
// that we want to be called when everything is done.
// in this case that function returns a string of html, that we can
// then add to the DOM.
Nation(data, function(html){
var el = document.getElementById('tableArea');
el.innerHtml(html);
});