setTimeout时间设置为0详细解析


Posted in Javascript onMarch 13, 2018

前言

本文主要给大家介绍了关于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有一些妙用,但是他确实是在宏观任务队列中新增任务了,所以万万不能滥用啊。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript setTimeout和setInterval 的区别
Dec 08 Javascript
关于jquery性能最佳实践的讨论,与求教
Mar 30 Javascript
JS实现点击图片在当前页面放大并可关闭的漂亮效果
Oct 18 Javascript
jQuery如何将选中的对象转化为原始的DOM对象
Jun 09 Javascript
node.js+Ajax实现获取HTTP服务器返回数据
Nov 26 Javascript
node.js中的console.timeEnd方法使用说明
Dec 09 Javascript
自己动手写的jquery分页控件(非常简单实用)
Oct 28 Javascript
AngularJS 中使用Swiper制作滚动图不能滑动的解决方法
Nov 15 Javascript
vue proxyTable 接口跨域请求调试的示例
Sep 12 Javascript
利用jqprint插件打印页面内容的实现方法
Jan 09 Javascript
vue实现分环境打包步骤(给不同的环境配置相对应的打包命令)
Jun 04 Javascript
html5调用摄像头截图功能
Jan 18 Javascript
vue-cli脚手架config目录下index.js配置文件的方法
Mar 13 #Javascript
用vue写一个仿简书的轮播图的示例代码
Mar 13 #Javascript
vue-cli脚手架引入图片的几种方法总结
Mar 13 #Javascript
解决vue-cli创建项目的loader问题
Mar 13 #Javascript
浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法
Mar 13 #Javascript
基于vue.js实现的分页
Mar 13 #Javascript
微信小程序中实现手指缩放图片的示例代码
Mar 13 #Javascript
You might like
joomla内置的表单验证功能使用方法
2010/06/11 PHP
PHP解压ZIP文件到指定文件夹的方法
2016/11/17 PHP
PHP生成图片缩略图类示例
2017/01/12 PHP
javascript读取xml
2006/11/04 Javascript
JavaScript对象、属性、事件手册集合方便查询
2010/07/04 Javascript
jquery ui dialog ie8出现滚动条的解决方法
2010/12/06 Javascript
『JavaScript』限制Input只能输入数字实现思路及代码
2013/04/22 Javascript
浅析JavaScript中的隐式类型转换
2013/12/05 Javascript
推荐JavaScript实现继承的最佳方式
2014/11/11 Javascript
21个JavaScript事件(Events)属性汇总
2014/12/02 Javascript
JavaScript中遍历对象的property的3种方法介绍
2014/12/30 Javascript
js树插件zTree获取所有选中节点数据的方法
2015/01/28 Javascript
jQuery过滤选择器经典应用
2016/08/18 Javascript
Javascript实现图片懒加载插件的方法
2016/10/20 Javascript
vue-router路由简单案例介绍
2017/02/21 Javascript
JQuery 进入页面默认给已赋值的复选框打钩
2017/03/23 jQuery
layui当点击文本框时弹出选择框,显示选择内容的例子
2019/09/02 Javascript
CountUp.js实现数字滚动增值效果
2019/10/17 Javascript
python发送邮件的实例代码(支持html、图片、附件)
2013/03/04 Python
PyQT实现多窗口切换
2018/04/20 Python
Django框架模板注入操作示例【变量传递到模板】
2018/12/19 Python
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
Python tensorflow实现mnist手写数字识别示例【非卷积与卷积实现】
2019/12/19 Python
升级keras解决load_weights()中的未定义skip_mismatch关键字问题
2020/06/12 Python
pytorch实现查看当前学习率
2020/06/24 Python
PyCharm+Miniconda3安装配置教程详解
2021/02/16 Python
Fossil加拿大官网:化石手表、手袋、首饰及配饰
2019/04/23 全球购物
EJB3推出JPA的原因
2013/10/16 面试题
自动化专业个人求职信范文
2013/11/29 职场文书
党员学习十八大感想
2014/01/17 职场文书
个人房屋买卖协议书(范本)
2014/10/04 职场文书
学前教育见习总结
2015/06/23 职场文书
python 实现的截屏工具
2021/05/08 Python
详解CSS故障艺术
2021/05/25 HTML / CSS
php修改word的实例方法
2021/11/17 PHP
二维码条形码生成的JavaScript脚本库
2022/07/07 Javascript