详解js中的setTimeout()函数

       在js中,setTimeout()函数是全局变量,无论在哪里它都是全局变量而不是局部变量。所以下面这个例子的结果可能让你大吃一惊:

 

function A() {
    this.b = function() {
        console.log(1)
    }
}
var c = A()
setTimeout(c.b, 10) 

        可能有些人认为上面这个例子输出的结果是1,但是结果是undefined。这是因为setTImeout()函数是全局变量,它把里面的c.b发到全局变量中,而全局变量中没有b这个属性,所以会报undefined错误。正确的做法是要实例化类,也就是new一个类。

 

       在js中,setTimeout()函数的运行机制是这样的,setInterval()函数也一样。将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。这意味着,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。·

        每一轮Event Loop时,都会将“任务队列”中需要执行的任务,一次执行完。setTimeout和setInterval都是把任务添加到“任务队列”的尾部。因此,它们实际上要等到当前脚本的所有同步任务执行完,然后再等到本次Event Loop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。

        所以如果前面有一个函数被阻塞了,则一直等待该函数执行完才能运行。因为js是单线程的,所以比较容易会发生阻塞的。

        在setTimeout()函数中,最快的运行时间是4毫秒,即使将延迟参数写为0或者负数,它都不会立马的运行。在延迟参数为0或负数时,需要等待当前脚步的同步任务和event loop(即任务队列)执行完毕才开始执行,由于参数为0或者负数,只是比其他setTimeout()函数尽可能早的运行函数,而参数为0或者负数本身优先级相同。如:

 

setTimeout('console.log(1)',0)
console.log(2)

        返回的结果是2 1

 

 

setTimeout('console.log(1)',0)
setTimeout('console.log(2)',-1)
setTimeout('console.log(3)',-1)
setTimeout('console.log(4)',0)

        返回的结果是1 2 3 4

 

        在setTimeout()函数中,还有一点是要值得注意的。那就是它的第一个参数必须是需要编译的代码或者是一个函数方法。所以像上面的例子中,console.log()被单引号括起来变成一个字符串,在setTimeout中有一个eval()函数可以将字符串进行编译。如果我们将console.log()方法没有用单引号括起来,那么整个setTimeout()函数就会立即执行,而不会考虑有没有延迟参数。如我在美的的美云智数面试遇见过的这一道题一样:

 

console.log(1)

setTimeout(console.log(2),0)
  
console.log(3)
  
setTimeout(console.log(4),-1)


        返回的结果是1 2 3 4,如果将单引号括起来,返回的结果是1 3 2 4

 

        在js中想要清除setTimeout定时器,需要clearTimeout()这个函数。具体用法如下所示:

 

var a = setTimeout('console.log(1)', 1)
clearTimeout(a)

        最后贴出一道题看看毕业了没有,对比下面三段代码,看分别输出上面:

 

 

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

 

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

 

for (var i = 0; i < 3; i++) {
    setTimeout((function(i) {
        return function() {
            console.log(i);
        };
    })(i), 0);
    console.log(i);  
}

 

 

 

 

 

        这道题设计了一些js的作用域的问题,我会专门写一篇文章介绍es5中作用域和es6中的作用域发生了哪些变化。

        本文参照这两个网站:详解setTimeout()函数   你所不了解的setTimeout()函数

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值