为什么JS重复创建定时器会导致动画加速、无法终止?

BENCJL
  • 12

在B站自学黑马程序员的JS教程(https://www.bilibili.com/vide...)。这里讲到定时器设置动画,如果设置了多个定时器会导致动画无法终止,视频说的不太明白。代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <style>
        div {
            position: absolute;
            top: 50px;
            left: 0;
            background-color: pink;
        }
    </style>
</head>

<body>
    <button>btn</button>
    <div>animate box</div>
    <script>
        var btn = document.querySelector('button');
        var div = document.querySelector('div');

        function animate(obj, end) {
            //clearInterval(obj.timer);// bug补救

            obj.timer = setInterval(function () {
                if (obj.offsetLeft >= end) {
                    clearInterval(obj.timer);
                } else {
                    // 如果连续点击btn,那么div加速向右运动,而且这行代码可以让 div停止运动
                    //obj.style.left = obj.offsetLeft + 1 + 'px';
                }
                // 如果连续点击btn,那么div加速向右运动,而且这行代码会导致 div不能停止运动
                obj.style.left = obj.offsetLeft + 1 + 'px';
            }, 10);
        }

        btn.addEventListener('click', function () {
            animate(div, 300);//div向右运动300px
        });
    </script>
</body>

</html>

没有头绪,看了两篇文章也没想明白动画停不了是啥原因。不管几个定时器,都应该按照end=300px来终止动画吧?求助大佬~~

回复
阅读 407
2 个回答

因为同一时刻 obj.timer 的值只能有一个clearInterval 只能关掉它遇到的这一个obj.timer对应的定时器。
考虑连续执行两次 animate 的情形:

  1. animate生成了定时器,该定时器的intervalID0
  2. 把这个 intervalID 赋给 obj.timer,至此 obj.timer = 0
  3. animate又生成了定时器,该定时器的intervalID1
  4. 把这个 intervalID 赋给 obj.timer,至此 obj.timer = 1
这时候执行 clearInterval(obj.timer),只能清空 intervalID = 1 的那个定时器,而为 0 的定时器成为“野生”定时器,会无限制地跑下去。

然后,考虑 obj.style.left = 这句代码的所处位置:

  • 如果是放在 else 分支里,那么“野生”定时器调用回调函数的时候,距离超过 300 就进了 if 分支,不会运行赋值代码;
  • 如果是放在 else 分支外,那么“野生”定时器调用回调函数的时候,距离超过 300 就进了 if 分支……然后继续运行分支外的代码,也就是赋值代码,动画会继续;
  • 另一种情况是 if 里面 return 了,也可以防止动画继续,这属于短路写法,按下不表。

setInterval不会清除定时器队列,每重复执行1次都会导致定时器叠加
给你个建议:setInterval前先clearInterval

、、、、
、、、、
 clearInterval(obj.time)
 obj.timer = setInterval(function () {、、、、
、、、、
宣传栏