【问题标题】:javascript loop freezes browser and can't see change before loopjavascript循环冻结浏览器并且在循环之前看不到变化
【发布时间】:2018-03-08 20:17:07
【问题描述】:

我有一个简单的 javascript 循环,如下所示:

function runCode() {
    $("#sample-span").removeAttr("style");
    for (var i = 0; i < 100000; i++) {
        console.log(new Date());
    }
    $("#sample-span").toggleClass("colorized");
}

页面中的切换类 span 如下:

<span id="sample-span" style="color: orange;">Sample Text</span>
<input type="button" value="click to run" onclick="runCode()" />

<style>
span {
    color: blue;
}
.colorized {
    color: red;
}
</style>

问题是当循环运行时页面冻结并且看不到跨度颜色的变化。

我该如何解决这个问题?

jsfiddle link

更新

亲爱的,console.log(new Date()); 只是一个示例,您假设这里正在运行繁重的 javascript 进程。

【问题讨论】:

  • 你为什么要记录new Date() 100000 次?那是非常昂贵的。
  • 亲爱的@GhassenLouhaichi,这只是一个示例,假设这里正在运行繁重的javascript procces。
  • 那么你必须将你的进程拆分成异步代码。

标签: javascript loops for-loop freeze


【解决方案1】:

在运行繁重的过程之前,您必须在更改颜色后添加一个小延迟:

function runCode() {
  $("#sample-span").toggleClass("colorized");
  setTimeout(runTask,10)
}

function runTask(){
    for (var i = 0; i < 100000; i++) {
    console.log(new Date());
  }
  $("#sample-span").toggleClass("colorized");
}

JSFiddle

【讨论】:

  • 这可行,但浏览器仍然冻结。有什么办法可以防止浏览器死机?
  • 你不能。 Javascript本质上是阻塞的,如果您运行繁重的进程,浏览器会停止并冻结,这是正常的
  • 好吧,您可以通过为繁重的过程的每个部分设置 1 毫秒的超时,人为地减慢进程来解决冻结问题: setTimeout(function(){ console.log(new Date()) ; },1);
  • 谢谢。我有一个浏览器冻结,修复是循环外的const now = new Date(),加上setTimeout(, 0)。不过,它仍然会冻结 2-3 秒。
【解决方案2】:

您的代码的问题在于 javascript 任务队列在执行 DOM 操作之前会执行您的函数中的所有可用代码。这意味着注册了类切换调用,执行循环,然后连续执行切换,因此您看不到颜色变化。

您需要做的是将函数的第二部分发送到任务队列的末尾,如下所示:

function runCode() {
    $("#sample-span").toggleClass("colorized");
    // allows the first toggle to execute and sends the loop and the second
    // toggle to the end of the task queue
    setTimeout(function() {
        for (var i = 0; i < 5000; i++) {
            console.log(new Date());
        }
        $("#sample-span").toggleClass("colorized");
    }, 0);
}

我已经减少了迭代次数以减少浏览器锁定,您仍然可以看到颜色变化。

【讨论】:

    【解决方案3】:

    你实际上想做什么?如果您希望文本显示为红色,然后在指定时间后切换回来,您真正需要的是 setTimeout。

      $("#sample-span").toggleClass("colorized");
    
      setTimeout(function() { $("#sample-span").toggleClass("colorized") }, 1000);
    

    【讨论】:

      【解决方案4】:

      这是因为您在单击按钮时切换了两次课程。 如果您想在完成后更改跨度的颜色,请编写:function runCode() { $("#sample-span").toggleClass("colorized"); for (var i = 0; i < 100000; i++) { console.log(new Date()); } }

      【讨论】:

      • 因为我想切换颜色两次
      • 虽然您想切换两次可能是真的,但该人确实在他的帖子中指定了“如果您想在完成后更改颜色”,没有理由拒绝这个答案。它 100% 正确。您并没有真正指定您希望在点击时发生什么,它可能会被解释为任何一种方式。
      • 我认为他在@Dellirium 的帖子中说得很清楚。这是一个不正确的答案,丝毫没有解决 OP 面临的问题
      • 好的,什么时候是第一次,什么时候是第二次?因为您的代码使其切换两次,这就是您看不到更改的原因。 @Shard 他告诉:“问题是当循环运行时页面冻结并且看不到跨度颜色的变化。” - 我编写了代码,您可以看到颜色正在变化:)
      • @Shard 不,事实上,他非常晦涩,没有任何地方说他想在代码运行时“显示颜色”,你只能这样解释......他可能想要运行代码并保持我们所知道的颜色。它称为切换,因此您再次单击它以再次运行它并将其关闭。谁知道,没有说明,我很确定 Radovan 就是这么想的,所以 OP 需要澄清他的帖子,而且由于他在这个答案时没有,因此它不是不正确的。我不是说它是 OP 想要的,假设他做了或没有这样做是错误的......
      猜你喜欢
      • 2017-05-20
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 1970-01-01
      • 2012-09-06
      • 2017-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多