javascript中setTimeout

1. settimeout用法

1.1 基本使用

语法: setTimeout(code,millisec)
code必填,调用函数;millisec非必填,如果不填就认为是0。settimeout()表示millisec毫秒后把code的代码放到执行队列(注意不是立即执行,后面会讲到)
例子:

let timeout2 = setTimeout(() => {
    console.log('haha')
}, 1000);

1000ms后会输出‘haha’
作为定时器使用

let test = function(){
        console.log('wait a moment', i)
            i++
          timeout3 = setTimeout(() => {
            test() 
           }, 3000);
           if(i === 10){
            clearTimeout(timeout3)
        }
        
        
}
test()

上面这段程序会定时输出打印的话:wait a moment0,1,2…

1.2 有关执行队列

以前一直认为写了setTimeout(fn, millisec)这段代码之后,fn就一定会再millisec后执行,其实这是不对的,看下面的例子:

console.log('now time:', Date.parse(new Date()))
setTimeout(() => {
    console.log('execute after 10s, now time', Date.parse(new Date()))
    let now = Date.parse(new Date())
    while(Date.parse(new Date()) - now < 10000){}
    
}, 10000);
setTimeout(() => {
    console.log('execute after 10s? now time:', Date.parse(new Date()))
}, 10000);

这段代码执行结果:
now time: 1644246966000
execute after 10s, now time 1644246976000
execute after 10s? now time: 1644246986000
可以发现后面的setTimeout()并没有按照预期在10000ms之后执行,而是等待第一个setTimeou()执行之后再执行

这也就解释了setTimeout()定义的millisec并不是执行时间,而是放到执行队列的时间,有关执行队列不明白的可以看这篇文章

2. setTimeout执行顺序

2.1 基础

首先需要明白的是js会执行完同步代码,然后才执行执行队列的顺序,如果执行队列只有setTimeout,执行顺序是按照放入队列的顺序执行的:millisec小的先执行,如果millisec相同,按照代码写的顺序执行

console.log('now time:', Date.parse(new Date()))
setTimeout(() => {
    console.log('execute after 10s, now time', Date.parse(new Date()))
    let now = Date.parse(new Date())
    // while(Date.parse(new Date()) - now < 10000){}
    
}, 10000);
setTimeout(() => {
    console.log('execute after 10s? now time:', Date.parse(new Date()))
}, 10000);

打印结果:
now time: 1644247542000
execute after 10s, now time 1644247552000
execute after 10s? now time: 1644247552000
上面的例子把阻塞程序注释掉,millsec相同,会先执行前面先写的setTimeout,注意打印的时候now time看起来是一样的,大概是因为时间间隔太近,约等于相同时间,=

2.2 经典例子

for(var i = 0; i<3;i++){

    console.log('i max 3 no  brackets', i)
    setTimeout(() => {
        console.log('i max 3 with brackets',i)
    }, 1000);
}
for(var i=0; i<10;i++){
    console.log('i max 10 no brackets', i)
    setTimeout(() => {
        console.log('i max 10 with brackets', i)
    }, 0);
}

执行结果:
i max 3 no brackets 0
i max 3 no brackets 1
i max 3 no brackets 2
i max 10 no brackets 0
i max 10 no brackets 1
i max 10 no brackets 2
i max 10 no brackets 3
i max 10 no brackets 4
i max 10 no brackets 5
i max 10 no brackets 6
i max 10 no brackets 7
i max 10 no brackets 8
i max 10 no brackets 9
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 10 with brackets 10
i max 3 with brackets 10
i max 3 with brackets 10
i max 3 with brackets 10
这个例子验证了前面的说法,执行顺序:
同步代码>setTimeout的millisec小的>setTimeout的millsec大的
另外关注到这里的i的输出,会发现setTimeout输出的都是10,这是因为使用了var定义变量,循环的i是同一个,等到执行setTimout的时候i已经变成了10,如果想要让setTimeout输出每次循环进入的时候的i的值,可以通过let解决,let认为花括号就是一个作用块,而var是es5中的语法,只认为function是一个作用域,不认识花括号,具体的解释可以参考我的这篇文章

3. 和promise的执行顺序

先说结论:
同步代码和promise里面的同步代码是等价的 > then里面的代码 > 外部的settimeout setTimeout中同样的millisec,执行顺序依据第二个参数排序,如果第二个参数相同,那就按照代码编写顺序排序
看例子:

setTimeout(() => {
 console.log('外部settimeout执行第一次')   
});

new Promise((resolve)=>{
    console.log('马上执行for循环啦')
    setTimeout(() => {
     console.log('promise里面同步代码执行settimeout')   
    });
    resolve()
}).then(() =>{
    console.log('进入then循环')
})
console.log('循环结束啦')
setTimeout(() => {
    console.log('外部settimeout执行第二次')   
   });

输出结果:
马上执行for循环啦
循环结束啦
进入then循环
外部settimeout执行第一次
promise里面同步代码执行settimeout
外部settimeout执行第二次

4. 总结

1、setTimeout(fn, millisec)表示的是millisec之后把fn放入执行队列,具体执行时间根据执行队列之前的执行情况决定,不一定是millisec之后就会执行
2、执行顺序:
同步代码和promise里面的同步代码是等价的 > then里面的代码 > 外部的settimeout setTimeout中同样的millisec,执行顺序依据第二个参数排序,如果第二个参数相同,那就按照代码编写顺序排序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值