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 showModalDialog 多层模态窗口实现页面提交及刷新的代码
Nov 28 Javascript
jQuery操作input type=radio的实现代码
Jun 14 Javascript
jQuery动画效果-slideUp slideDown上下滑动示例代码
Aug 28 Javascript
JavaScript修改作用域外变量的方法
Mar 25 Javascript
javascript滚轮控制模拟滚动条
Oct 19 Javascript
Javascript中的神器——Promise
Feb 08 Javascript
vue脚手架中配置Sass的方法
Jan 04 Javascript
详解Chart.js轻量级图表库的使用经验
May 22 Javascript
基于layui轮播图满屏是高度自适应的解决方法
Sep 16 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
Nov 14 Javascript
微信小程序 this.triggerEvent()的具体使用
Dec 10 Javascript
Js逆向实现滑动验证码图片还原的示例代码
Mar 10 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
关于PHP结束标签的使用细节探讨及联想
2013/03/04 PHP
php读取文件内容到数组的方法
2015/03/16 PHP
php 生成签名及验证签名详解
2016/10/26 PHP
深入理解Yii2.0乐观锁与悲观锁的原理与使用
2017/07/26 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
jquery easyui的tabs使用时的问题
2010/03/23 Javascript
浅析JQuery获取和设置Select选项的常用方法总结
2013/07/04 Javascript
简单的Jquery全选功能
2013/11/07 Javascript
javascript实现的元素拖动函数宿主为浏览器
2014/07/21 Javascript
一个JavaScript递归实现反转数组字符串的实例
2014/10/14 Javascript
详解JavaScript中的forEach()方法的使用
2015/06/08 Javascript
JQuery导航菜单选择特效
2016/04/11 Javascript
基于VUE选择上传图片并页面显示(图片可删除)
2017/05/25 Javascript
前端html中jQuery实现对文本的搜索功能并把搜索相关内容显示出来
2017/11/14 jQuery
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
2018/08/09 jQuery
vue组件 keep-alive 和 transition 使用详解
2019/10/11 Javascript
JS实现判断移动端PC端功能
2020/02/21 Javascript
JavaScript中CreateTextFile函数
2020/08/30 Javascript
Python字典数据对象拆分的简单实现方法
2017/12/05 Python
Django中的Model操作表的实现
2018/07/24 Python
python lxml中etree的简单应用
2019/05/10 Python
Django 开发环境与生产环境的区分详解
2019/07/26 Python
xadmin使用formfield_for_dbfield函数过滤下拉表单实例
2020/04/07 Python
使用Python将Exception异常错误堆栈信息写入日志文件
2020/04/08 Python
plt.figure()参数使用详解及运行演示
2021/01/08 Python
Python3+Django get/post请求实现教程详解
2021/02/16 Python
澳大利亚制造的蜡烛和扩散器:Glasshouse Fragrances
2018/05/20 全球购物
.NET程序员的数据库面试题
2012/10/10 面试题
酒吧创业计划书
2014/01/18 职场文书
俄罗斯商务邀请函
2014/01/26 职场文书
高中自我评价范文
2014/01/27 职场文书
《黄河颂》教学反思
2014/02/07 职场文书
讲解员培训方案
2014/05/04 职场文书
Spring Data JPA框架自定义Repository接口
2022/04/28 Java/Android
不想升级Win11?教你彻底锁定老版Windows系统的方法(附下载地址)
2022/09/23 数码科技
Java中的Kafka为什么性能这么快及4大核心详析
2022/09/23 Java/Android