setTimeout时间设置为0时,发生了什么?

1.setTimeout是什么?

setTimeout(fn,millisec) 方法用于在指定的毫秒数后调用函数或计算表达式。

setTimeout()只执行fn一次,到底什么时候执行取决于第二个参数millisec设定的毫秒数
举个例子:

setTimeout(function(){
	console.log('我是setTimeout')
},1000)

正常情况下,‘我是setTimeout’这句话并不会马上输出而是等1000毫秒以后在浏览器的控制台上输出。

2.js是单线程

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

以上代码得到的结果是2,3,1,这似乎不按照逻辑,定时器应该等待0毫秒就不等待直接输出,为什么1却在最后面输出呢?
这就要搞清楚一个很重要的概念:js是单线程,单线程就意味着,所有任务都需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
而浏览器的内核是多线程的,他们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:jsvascript引擎线程,GUI渲染线程,浏览器事件触发线程。

  • javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。
  • GUI渲染线程负责渲染浏览器界面,当界面需要重绘或由于某种操作引发回流时,该线程就会执行。但需要注意GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
  • 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事情可来自js引擎当时执行的代码快如setTimeout,也可来自浏览器内核的其他线程如鼠标点击,AJAX异步请求,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理

setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说尽可能早得执行。它在‘任务队列’的尾部添加一个事件,因此要等到同步任务和‘任务队列’现有的事件都处理完,才会得到执行。

HTML5标准规定了setTimeout的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变化(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()

需要注意的是,setTimeout()只是将事件插入了‘任务队列’,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时时间很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行

3.setTimeout的用途

函数去抖

让一个函数在一定间隔内没有被调用时,才开始执行被调用方法。比如当你在使用 google 搜索内容的时候,有些关键词输入到一半,谷歌会展示一个可选列表,根据你当前输入的内容作出的一个猜测联想。需要监听文字改变,每一次改变都会调用一次回调函数,现在需要的一种实现是在用户停止键盘事件一段时间后,去发送一个请求。

var debounce = function(method, context) {
clearTimeout(method.tId);
method.tId = setTimeout(function(){
 method.call(context);
},100);
}
轮询任务

js中可以使用setInterval开启轮询,但是这种存在一个问题就是执行间隔往往就不是你希望的间隔时间。

比如有个轮询任务间隔是100ms,但是执行方法的时间需要450ms,那么在200ms、300ms、400ms本来是计划中执行任务的时间,浏览器发现第一个还未执行完,那么就会放弃2、3、4次的任务执行,并且在500ms之后再次执行任务,这样的话,其实再次执行的间隔就只有50ms。使用setTimeout构造轮询能保证每次轮询的间隔。

setTimeout(function () {
 console.log('我被调用了');
 setTimeout(arguments.callee, 100);
}, 100);
延迟js引擎的调用
var div = document.createElement('div');
div.innerHTML = '我是一个div';
div.setAttribute('style', 'width:200px; height:200px;background-color:#f00; ');
document.body.appendChild(div);
setTimeout(function() {
 console.log('我被调用了');
}, 1000);

参考链接:https://www.jb51.net/article/136335.htm

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值