javascript之定时器

 在JavaScript中,定时器看似简单,其实挺复杂的,与JavaScript的运行机制。我们都知道JavaScript是单线程的,这里说的单线程指的是JavaScript引擎是单线程的,浏览器是多线程的。JavaScript的运行机制不是本篇文章讨论范围,本文主要讨论setTimeout。定时器很常用,也很容易出现在面试题中,这篇文章将围绕定时器的语法,常见例子,以及一些要注意的地方和容易弄错的地方。

一、setInterval语法

 语法setInterval(str,time);setInterval(function,time,parmam1,param2…);第一个参数为字符串或者函数,第二个参数为定时的时间,第三个参数可以作为传给函数的参数(可选)。返回值为一个定时器的ID(数字);一般将这个ID传给clearinterval()清除定时器。setInterval定时器是间歇性调用,即每隔设定的时间调用一次,在不加干涉的情况下,间歇调用将会一直执行到页面卸载。例如

setInterval(function(){
    console.log(1);
},2000);

每隔2秒打印一次值,这段如果不使用clearInterval清除定时器则会一直输出1

二、setTimeout语法

 setTimeout的语法跟setInterval一样,只不过setTimeout不是间歇调用,而是超时调用,而是在设定时间是执行一次定时器里面的代码,注意是执行一次。清除定时器使用clearTimeout().例如

setTimeout(function(){
    console.log(1);
},2000);

这段代码只打印一次1,在编写程序过程中建议多使用setTimeout代替setInterval。

三、执行机制

 setInterval与setTimeout是异步执行的,也就是说在同一个循环中,等到其他同步代码执行完后,再执行定时器的代码。如这段代码:

console.log(1);
setTimeout(function(){
    console.log(2);
},1000);
console.log(3);

输出的顺序是1,3,2,而不是1,2,3;定时器中设定的时间不一定就是在1秒就打印出2,而是等其他同步代码执行完后,再等待一秒打印。如果前面的代码耗时很长那么可能要很久才执行。那么现在来理解一下

setTimeout(f,0);

当定时为0的时候是立即打印吗?当然不是,就像前面说的,它会等其他同步任务执行完后再执行,那么将时间定为0就表示当其他同步任务执行完后立即执行定时器里面的代码。setTimeout(f,0)的应用:
1. 用来改变事件的执行顺序:例如我们想要在表单中输入英文字母时立即将它转换为小写字母,加如我们使用这段代码:

document.getElementById('in').onkeypress=function(event){
            this.value=this.value.toLowerCase();
        }

那么它只能在键盘输入下一个字符时才把上一个字符变为小写,但我们需要的是输入字符立即转换。此时可以使用setTimeout(f,0)解决这个问题

document.getElementById('in').onkeypress=function(event){
            var _this=this;
            setTimeout(function(){
                _this.value=_this.value.toLowerCase();
            },0);   
        }

2.由于setTimeout(f,0)实际上意味着,将任务放到浏览器最早可得的空闲时段执行。所以在处理那些计算量大、耗时长的任务,常常会被放到几个小部分(容易造成阻塞),分别放到setTimeout(f,0)里面执行。简单来讲就是任务拆分。

//写法一
var div=document.getElement('div1');
        for(var i=0xA00000;i<0xFFFFF;i++){
            div.style.backgroundColor='#'+i.toString(16);
        }
//写法二
    var div=document.getElement('div1');
        var timer;
        var i=0x100000;
        function f(){
            timer=setTimeout(f,0);
            div.style.backgroundColor='#'+i.toString(16);
            if(i++==0xFFFFF) clearTimeout(timer);
        }
        timer=setTimeout(f,0);

四、setTimeout与闭包

 经过前面的分析,现在我们来看一下小例子

for(i=0;i<5;i++){
    console.log(i);
}

相信这段代码输出什么大家肯定不陌生吧。那么接下来这段代码呢?

for(i=0;i<5;i++){
    setTimeout(function(){
        console.log(i);
    },1000);
}

没错,这段代码并不会如我们所愿的输出0,1,2,3,4;而是输出连续输出5个5。为什么呢?如果我们在setTimeout后面再加一个console.log(i),通过控制台可以看到,先输出0、1、2、3、4,再输出5个5.

for(i=0;i<5;i++){
    setTimeout(function(){
        console.log(i);
    },1000);
    console.log(i);
}//

这就跟我前面说的setTimeout是异步的有关,它会等整个循环同步任务执行完后再执行。那么我们可以通过闭包来解决问题,每循环一次,便立即将i值传入自执行函数中,传给setTimeout。

for(i=0;i<5;i++){
    (function(i){
            setTimeout(function(){
            console.log(i);
        },1000);
    })(i);
}

为什么这下面这段代码失败了呢?

for(i=0;i<5;i++){
    (function(){
            setTimeout(function(){
            console.log(i);
        },1000);
    })(i);
}

这是因为没有将每一次循环的i值传给setTimeout.

五、正常任务和微任务

 我们来考虑一个问题,当setTimeout和Promise同时出现时,两个都是异步执行的,那么谁先执行呢?考虑下面代码:

console.log(1);
setTimeout(function(){
    console.log(2);
},0);
Promise.resolve().then(function(){
    console.log(3);
});

通过运行我们可以发现输出的结果是1、3、2;即setTimeout在Promise之后执行。原因是setTimeout是正常任务,Promise是微任务。setTimeout是在下一次Event Loop中执行,而Promise是在本轮Event Loop结束时执行。正常任务有

  • setInterval
  • setTimeout
  • setImmediate
  • I/O
  • 各种事件(比如鼠标单击事件)的回调函数

六、一些注意事项

 还记得上面的这个例子吗

document.getElementById('in').onkeypress=function(event){
            var _this=this;
            setTimeout(function(){
                _this.value=_this.value.toLowerCase();
            },0);   
        }

在这里将当前this保存下来,不然在settimeout运行时this会指向全局对象。现在来详细了解一下setTimeout指向的问题。由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined。例如这段代码

var a=1;
function obj(){
    this.a=2,
    this.getA=function(){
        console.log(this.a);
    }

    this.getAlate=function(){
        setTimeout(function(){
            console.log(this.a);
        },1000);
    }
}
var o=new obj();

o.getA();//2
o.getAlate();//1 this指向全局window

从输出结果可看出,setTimeout中的this指向了window对象。解决这种问题一般有三种方法

  • 将this保存下来,通过闭包访问
var a=1;
function obj(){
    var that=this;//保存this
    this.a=2,
    this.getA=function(){
        console.log(this.a);
    }
    this.getAlate=function(){
        setTimeout(function(){
            console.log(that.a);
        },1000);
    }
}
var o=new obj();
o.getA();//2
o.getAlate();//2
  • 使用bind函数改变this指向

var a=1;
function obj(){
    this.a=2,
    this.getA=function(){
        console.log(this.a);
    }
    this.getAlate=function(){
        setTimeout(function(){
            console.log(this.a);
        }.bind(this),1000);//绑定this
    }
}
var o=new obj();

o.getA();//2
o.getAlate();//2
  • 使用es6的箭头函数
var a=1;
function obj(){
    this.a=2,
    this.getA=function(){
        console.log(this.a);
    }
    this.getAlate=function(){
        setTimeout(()=>{
            console.log(this.a);
        },1000);
    }
}
var o=new obj();
o.getA();//2
o.getAlate();//2

参考文章:
MDN文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript时钟定时器是一种利用JavaScript编程语言实现的定时调用函数的方法。通过使用定时器,可以在网页上创建实时更新的时钟效果。在给定的时间间隔内,定时器会定期调用指定的函数,以更新时钟显示。定时器通常用于制作在线时钟、图片轮播、广告弹窗等自动执行的功能。 在给出的HTML代码中,通过使用window.onload函数,当页面加载完成后,设置了一个定时器(timer)来调用show函数,实现页面上时钟动态更新的效果。show函数通过获取div元素的id并将当前时间转换为字符串的形式,实时更新div内的内容。同时,还提供了开始和停止按钮,分别用于开启和清除定时器(timer)。当点击开始按钮时,会重新启动定时器,调用show函数更新时钟显示;当点击停止按钮时,会清除定时器,停止时钟的更新。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [JavaScript事件添加定时器](https://download.csdn.net/download/qq_62259825/85664312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [JavaScript-可控制的时钟(定时器)](https://blog.csdn.net/qq_40757071/article/details/82784848)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值