当浏览器窗口最小化时,JS会发生什么?

4

JS代码是否会继续执行,但是在用户再次查看浏览器窗口/选项卡之前不会呈现任何HTML内容?

运行下面的示例,将浏览器窗口留下几个时间间隔,然后回来,似乎有什么东西排队等待?这是什么?为什么?我能停止它吗?

setInterval(updateTiles, 4000);

function updateTiles() {

  var boxes, randomIndex, randomBox;

  boxes = $(".box");

  randomIndex = Math.floor(getRandomArbitrary(0, boxes.length));
  randomBox = $(boxes[randomIndex]);

  $(randomBox).toggleClass("flipper");
}

function getRandomArbitrary(min, max) {
  return Math.random() * (max - min) + min;
}
.box {
  width: 100px;
  height: 100px;
  background: blue;
  float: left;
  margin:10px;
}

.flipper {
  transition: 1.5s;
  transform-style: preserve-3d;
  transform: rotateX(360deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>


这取决于用户使用的浏览器/版本/设置。 - Luca Kiebel
@Luca 我认为这可能与浏览器行为有关,我尝试在Mozilla的文档中找到一些信息,但我只找到了一个可以与其他窗口/标签交互的API。 - Abs
我认为这是CSS动画。它们只在文档流上触发,因此如果你最小化了,就没有文档流,但你的计时器仍在运行并应用动画。 - Keith
setInterval 不会排队事件。 - Keith
@Abs,问题出在CSS过渡效果上,当浏览器浏览到其他页面时,它会将动画保留在内存中,直到您返回到动画网站。 - LellisMoon
3个回答

1

是的,似乎在Chrome中,使用setInterval的CSS转换会被“排队”,我有一个用d3制作的时钟问题,背景下更改秒针后,重新进入页面时会导致浏览器出现问题。

排队意味着(如您可以在此处更好地阅读),这些规则导致新转换的整个时间函数被使用,而不是跳到时间函数的中间,这可能会产生刺耳的效果。

实现可以进行的主要优化类别之一是在浏览器的合成器线程或进程上运行某些高价值属性(如transform和opacity)的动画,而不更新主Web内容线程上的样式或布局,除非需要最新的样式数据。该优化通常需要分配图形内存以显示正在动画化的元素的内容。实现应注意,Web内容不能通过使用大量动画或覆盖大面积元素(其中“大面积”可以根据预变换或后变换大小来定义)来触发不安全的内存处理。

我解决了这个问题,通过检查用户何时更改页面以及何时重新进入页面来启动和停止计时器。

正如您所看到的,如果我的文档不可见,我会停止setTimeout调用,并在文档可见时重新启动函数。

function getRandomArbitrary(min, max) {
  return Math.random() * (max - min) + min;
}

function updateTiles() {
  if(!document.hidden){
    console.log('the function is running');
    var boxes, randomIndex, randomBox;

    boxes = $(".box");

    randomIndex = Math.floor(getRandomArbitrary(0, boxes.length));
    randomBox = $(boxes[randomIndex]);

    $(randomBox).toggleClass("flipper");
    setTimeout(updateTiles, 4000);
  }else{
    console.log('stop the function');
  }
}

var restartTimer=function ()  {
        if (!document.hidden) {
            console.log('restart the function');
            updateTiles();
        }
    };

document.removeEventListener('visibilitychange',restartTimer);
document.addEventListener('visibilitychange',restartTimer);

updateTiles();
.box {
  width: 100px;
  height: 100px;
  background: blue;
  float: left;
  margin:10px;
}

.flipper {
  transition: 1.5s;
  transform-style: preserve-3d;
  transform: rotateX(360deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>


使用 setInterval 的事件是排队等待执行的,不,这并不是正在发生的事情。 - Keith

1

当窗口获取焦点时,setTimeout和setInterval将累积并一次性运行所有内容。对于排队的动画来说,这看起来很突兀,有时会出现卡顿。我建议使用window.requestAnimationFrame,它知道当前窗口的焦点状态。因此,您提供的动画或函数将不会执行。


似乎我的直觉是错误的,我刚刚执行了:setInterval(function(){console.log(performance.now())},2000)。我可以确认定期读数。我想这仍然不能改变requestAnimationFrame是正确方法的事实。感谢您的评论。 - ibrahim tanyalcin

1
这里的问题与setTimeout等无关,它们会在你请求的时间内正常运行,即使最小化也不会有任何排队。但是不会继续运行动画(因为那只是浪费),并且正如您可能知道的那样,CSS动画在应用动画类时触发。因此,当最小化时,您的.flipper类仍在更改,但是由于动画已暂停,直到从最小化状态恢复动画才会触发。尽管如此,执行Mr.Bruno建议的暂停计时器的操作似乎是个好主意,毕竟在不可见时翻转类有何意义呢?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接