解析setTimeout时间设置为0
1、开胃菜,setTimeout为何物
首先看一下w3school
上面对于setTimeout
的解释
setTimeout(fn,millisec) 方法用于在指定的毫秒数后调用函数或计算表达式。
很简单,setTimeout()
只执行 fn
一次,到底什么时候执行取决于第二个参数millisec
设定的毫秒数,所以很多人习惯上称之为延迟
,无非就是延迟一段时间后再执行里面的代码。
setTimeout(function(){
console.log('我是setTimeout');
}, 1000);
正常情况下,我是setTimeout
这句话并不会马上输出而是等1000毫秒以后会在浏览器的控制台输出。
2、主菜,js是单线程的
OK,看一个例子,这个例子的输出结果是什么?
setTimeout(function(){
console.log(1);
}, 0);
console.log(2);
console.log(3);
出乎一些人的意料,得到的结果竟然是2、3、1
。这似乎不按套路出牌啊,明明是等待了0毫秒也就是不等待直接输出啊,为啥1
却在最后输出了呢?
这就需要搞清楚一个很重要的概念:js是单线程的,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
其实很好理解,就像大家去超市买东西一样,所有买东西的人都需要在收银台排队结账,正常情况下每个收银台同一时间只能为一位顾客结账,这位顾客结账完成才能为下一位顾客服务。
而浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程
,GUI渲染线程
,浏览器事件触发线程
。
- javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。
- GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
- 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)
其实,当js代码执行遇到setTimeout(fn,millisec)
时,会把fn
这个函数放在任务队列中,当js引擎线程空闲时并达到millisec
指定的时间时,才会把fn
放到js引擎线程中执行。
setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()。
需要注意的是,setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。
3、甜品,setTimeout的妙用
其实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);
虽然setTimeout有一些妙用,但是他确实是在宏观任务队列中新增任务了,所以万万不能滥用啊。
解析setTimeout时间设置为0的更多相关文章
- 【转】 c#中两个DateTimePicker,一个时间设置为0:0:0,另一个设置为23:59:59
[转] c#中两个DateTimePicker,一个时间设置为0:0:0,另一个设置为23:59:59 stp1为第一个DateTimePicker this.dtp1.Value=this.dtp1 ...
- js中setTimeout() 时间参数为0
当看到下面 这种setTimeout 设置为0 写法的时候一脸懵逼,完全没用过. var fuc = [1,2,3]; for(var i in fuc){ setTimeout(function() ...
- Socket超时时间设置
你知道在 Java 中怎么对 Socket 设置超时时间吗?他们的区别是什么?想一想和女朋友打电话的场景就知道了,如果实在想不到,那我们就一起来来看一下是咋回事吧 设置方式 主要有以下两种方式,我们来 ...
- js中setTimeout()时间参数设置为0的探讨
起因源于一道前端笔试题: var fuc = [1,2,3]; for(var i in fuc){ setTimeout(function(){console.log(fuc[i])},0); co ...
- setTimeout的时间设为0的问题
javascript是单线程执行的,当某一段代码正在执行的时候,所有的后续任务都必须等待,形成一个队列, 一旦当前任务执行完毕,再从队列中取出下一个任务.这常被称为”阻塞式执行“. 如果代码中设定一个 ...
- 【C#】datetimepicker里面如何设置日期为当天日期,而时间设为0:00或23:59?
今天无意中发现要根据日期查询时间,datatimepicker控件会把时间默认成当前时间(当你的控件只显示日期时),这样查询出来的出来的数据会有误差,用来下面的办法成功设置日期为当天日期,而时间设为0 ...
- setTimeout设置为0的意义
今天再看 Promise 代码时,有个地方用到了setTimeOut函数,但是第2个参数设为0,顿时懵逼了,这是啥意思? function resolve(newValue) { value = ne ...
- CURL超时时间设置
一次完整的http请求,一般包含三个步骤: 通过DNS把域名解析成IP 通过IP地址连接到目标主机 获取目标主机数据(1.给目标主机输出http请求头,以\r\n\r\n结尾:2.获取目标主机传过来的 ...
- Django Celery定时任务和时间设置
1.Celery加入定时任务 Celery除了可以异步执行任务之外,还可以定时执行任务.在实例代码的基础上写个测试方法: #coding:utf- from celery.task.schedules ...
随机推荐
- Android原生代码与html5交互
一.首先是网页端,这个就是一些简单的标签语言和JS函数: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&q ...
- 学会配置nginx
一.作为一名开发人员,大家可能经常会用到服务器,但是一般线上的服务器可能都是公司公用的,而且线上的服务器一般也不是能随随便便给个人用的,所以部署本地服务器看来是一遍必不可少的事情和能力呀,所以,ngi ...
- zabbix-proxy搭建
环境: 因为公司需要监控远程客户机,但server端无法主动连接agent端,客户端可以连接公司ip 公司有固定ip,可以开放某个端口给zabbixserver,客户机agent端可以主动通过外网连接 ...
- 【转】判断点在多边形内(matlab)
inpolygon -Points inside polygonal region Syntax IN = inpolygon(X,Y,xv,yv)[IN ON] = inpolygon(X,Y,xv ...
- javascript:将URL的参数列表解析为一个对象
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Nginx+Geoserver部署所遇问题总结
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 该问题的最终解决离不开公司大拿whs先生的指点,先表示感谢. ...
- linux tar 压缩解压命令
tar命令: -c 压缩-x 解压缩-t 不解压的情况下查看文件内容-r 向压缩文件追加文件-u 更新压缩文件 以上参数必须和'-f'参数连用,且'-f'必须为最后一个参数,后接文档名 -z 对应gz ...
- Linq to SQL 中实现模糊查询
list = list.Where(i => i.Name.Contains(empName)).ToList();
- Cookie简述
1. Cookie是什么? Cookie(Cookies,浏览器缓存), 是指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密). 2. Cookie的作用: ...
- js、jQuery实现2048小游戏
2048小游戏 一.游戏简介: 2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...