防止 JavaScript 在大循环中锁定浏览器 [英] Prevent JavaScript from locking up browser on big loop

查看:30
本文介绍了防止 JavaScript 在大循环中锁定浏览器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要在浏览器中运行 2 亿次的循环.这是一个模拟器,几个人需要经常使用.运行大约需要15分钟,但在此期间,浏览器会频繁弹出此脚本占用时间过长"等警告,并在该功能期间完全挂起Firefox.这也意味着该页面不会更新我的状态指示器(它只是一个数字).

I have a loop which needs to be run 200 million times in a browser. It's a simulator which several people need to use regularly. It takes about 15 minutes to run, but during this time, the browsers will frequently pop up a warning with "this script is taking too long" etc., and it completely hangs Firefox during the function. This also means the page does not update my status indicator (which is just a number).

我在谷歌上搜索了javascript yield"并阅读了命中的前 4 页.有些人讨论了一个新的产量"关键字,但只有一个描述和示例,我觉得难以理解,例如包含 yield 关键字的函数是一个生成器.当你调用它时,它的形式参数被绑定到实际参数,但它的主体实际上并没有被评估".yield 是否会屈服于 UI?

I have googled "javascript yield" and read the first 4 pages of hits. Some discuss a new "yield" keyword, but there is only one description and example, which I find incomprehensible, e.g. "The function containing the yield keyword is a generator. When you call it, it's formal parameters are bound to actual arguments, but it's body isn't actually evaluated". Does yield yield to the UI?

我找到的少数解决方案之一是这篇旧帖子,它使用已弃用的被调用方参数和一个计时器来调用自身:http://www.julienlecomte.net/blog/2007/10/28/

One of the few solutions I did find is this old post which uses the deprecated callee argument and a timer to call itself: http://www.julienlecomte.net/blog/2007/10/28/

然而,上面的例子不包含任何循环变量或状态,当我添加它们时它会崩溃,我的最终结果总是零.

However, the above example doesn't contain any loop variables or state, and when I add these it falls apart, and my net result is always zero.

它也不进行分块,但我发现了一些其他示例,这些示例在每次迭代时都使用index % 100 == 0"进行分块.然而,这似乎是一种缓慢的方式.例如.这个:

It also doesn't do chunking, but I have found some other examples which chunk using "index % 100 == 0" on every iteration. However, this seems to be a slow way of doing it. E.g. this:

如何阻止密集的 Javascript 循环冻结浏览器

但是它没有任何方法可以更新进度,并且不会屈服于 UI(因此仍然会挂起浏览器).这是一个在执行过程中挂起浏览器的测试版本:

But it doesn't have any way to update progress, and doesn't yield to the UI (so still hangs the browser). Here is a test version which hangs the browser during execution:

<!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 始终为零(所以我认为存在一些范围问题):

and here is another attempt which the stats.a is always zero (So I presume there is some scoping issue):

<!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 小时试图让这个工作 - 要么我很笨,要么这很难.有什么想法吗?

I've spent 48 hours trying to get this working - either I am very dumb or this is very hard. Any ideas?

有几个人推荐了网络工作者.我尝试了几天让他工作,但我找不到一个类似的例子来传递一个数字等.下面的代码是我最后一次尝试让它工作,但结果总是 0,而它应该是 100000.即它失败的方式与我上面的第二个示例失败的方式相同.

Several people have suggested web workers. I tried several days to get his working, but I could not find a similar example which passes a number etc. The code below was my last attempt to get it working, but the result is always 0 when it should be 100000. I.e. it fails in the same way that my second example above fails.

spinMaster.html:

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

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

推荐答案

Web Workers 听起来是更好的解决方案.

Web workers sound like the better solution.

我写得很快,所以我不知道它是否有效.性能会很差...

I wrote this up quickly so i dunno if itll work. Performance will be very bad...

更改为与海报相同的格式.已测试

Changed to same format as poster. Tested

<!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 = 0.0;

    var index = 0;

    function workLoop() {

        index += 1;

        stats.a++;
        big = (big/3.6)+ big * 1.3 * big / 2.1;
        console.log(big);
        // Perform xml processing
        document.getElementById('result').innerHTML = stats.a;
        if (index < spins) {
            setTimeout(workLoop, 5); 
        }   

    }   



</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body onload="workLoop()">
<div id="result">result goes here.</div>
</body>
</html>

这篇关于防止 JavaScript 在大循环中锁定浏览器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆