js重复创建定时器的解决

20 篇文章 0 订阅


解决重复创建定时器的BUG

1. 问题描述

在点击事件中创建定时器,制作一些动画,如果重复点击,会导致动画的速度加快
如,下面的星星随机移动的主代码:

function f1() {
        var i = 0;//测试用,执行5次,就清除定时器
        var timerId = setInterval(function () {
            i++;
            my$("dv").innerHTML = "<span>☆</span>"
            var starObj = my$("dv").firstElementChild;
            var x = parseInt(Math.random() * 200 + 1);
            var y = parseInt(Math.random() * 200 + 1);
            starObj.style.color = "#fff";
            starObj.style.fontSize = "30px";
            starObj.style.position = "absolute";
            starObj.style.left = x + "px";
            starObj.style.top = y + "px";
            if (i >= 5) {
                clearInterval(timerId);
            }
            console.log(timerId);
            console.log("i"+"---(1)------"+i);//检测i的生存期
        }, 500);
        console.log("i"+"-----(2)----"+i);//检测i的生存期
    }

    my$("btn2").onclick = function(){
        console.log("i"+"-----(3)----"+i);//检测i的生存期
    };
    my$("btn").onclick = f1;

2. 问题分析

定时器创建后的id是存放在定时器函数的外部变量(点击事件处理函数的内部变量timerId)中的
在之前的定时器没有完成清除的时候,又有点击事件发生,调用事件发生函数,创建定时器
这个时候,又会申请空间,存放变量timerId,存放新的定时器的id值,虽然同名,但是并不冲突
这些存放定时器id值的变量,在点击事件处理函数看来,是局部变量
在定时器函数看来,是外部变量
这些变量不会在点击事件函数执行完后就销毁,而是会保存在内存中,供定时器函数使用
至于定时器清除后,这些变量是否存在,暂时不清楚,推测是会被销毁
反正这些变量也仅限于定时器函数和点击事件处理函数使用
基于此,尽管多个定时器被创建,但是最终也是能够成功地被清除
不过是会导致动画效果有异样罢了,比如看起来会加快

3. 解决思路

在每一次要创建定时器之前,判断是否已经有定时器在工作了,如果有,就删掉—>有则删之
还有一种思路就是,如果没有,就创建—>无则加之
至于用来存放timerId的,是变量或者是对象的属性,都可以实现
不过用变量的话,要注意变量的生存期
所以个人喜欢用对象的属性—>自定义属性(有点大材小用)或者点语法(方便)
下面是封装后的元素水平移动的代码:

/**
     * 实现元素水平移动
     * @param element 要操作的对象
     * @param target 目标位置,number,px为单位,但是请只传数字,left大小
     * @param step 每次定时器操作所移动的步长,number,px为单位,但是请只传数字
     * @param timeStep 定时器周期,number,ms为单位,但是请只传数字
     */
    function animate(element, target, step, timeStep) {
        if (element.timerId) {
            clearInterval(element.timerId);
        }
        element.timerId = setInterval(function () {
            var current = element.offsetLeft;
            var distance = Math.abs(current - target);
            //关键!!!定时器函数会保存所有的参数!所以要进行初始化处理!
            // 否则在反向的时候,step的值保留了上一次的负值,会反转成正值,循环往复,原地抖动
            step = Math.abs(step);
            step = distance > step ? step : distance;
            step = current > target ? -step : step;
            current += step;
            element.style.left = current + "px";
            if (current == target) {
                clearInterval(element.timerId);
                element.timerId = null;
            }
            console.log(current);
        }, timeStep);
    }

4. 几点补充

4.1

在上面的封装函数中,元素在current大于target的时候,会发生原地抖动的现象
原因是定时器函数会保存其参数的状态
所以step的值第一次翻转为负值
第二次再次反转,就变为正值
所以会出现原地抖动的现象
故,对参数进行初始化处理解决

4.2

对于有则删之和无则加之两种思路

  1. 有则删之----->会更新定时器
    每一次都会重新创建定时器,就是说如果先后创建两个定时器,那么后面的会更新掉前面的定时器
  2. 无则加之----->会保护当前的定时器工作
    当已经有定时器在工作了,那么之后的定时器创建申请都将不会通过
    直到当前定时器完成清除,才会重新开放接收创建请求

这种思想会在很多场景运用
具体孰优孰劣,尚无说法,根据需求选择即可
HOME

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值