# 走位setTimeout,回手掏Event Loop
栏目: JavaScript · 发布时间: 5年前
内容简介:本文仅是技术验证,记录,交流,不针对任何人。有冒犯的地方,请谅解。本文首发于https://vsnail.cn/static/doc/blog/setTimeout.html本想喝着估计大部分人都会知道第一个输出会是
本文仅是技术验证,记录,交流,不针对任何人。有冒犯的地方,请谅解。本文首发于https://vsnail.cn/static/doc/blog/setTimeout.html
本想喝着 coffee
,看着娃,过一个恬静的周六。 occasionally
,浏览到一段代码,觉的蛮有趣。
setTimeout(function(){console.log(1)},30) setTimeout(function(){console.log(2)},10) setTimeout(function(){console.log(3)},0) let now = new Date(); while(new Date() - now<100){ } console.log(0); 复制代码
估计大部分人都会知道第一个输出会是 0
(如果还不知道为什么 0
会先输出,也没有关系,看完整篇文章你就会知道了).
但是后面输出的顺序到底是 3>2>1
还是 1>2>3
,估计就有争议了。
回手掏,鬼刀一开看不见,走位走位,手里干
走位,走位(简单使用setTimeout)
想知道上面的答案?等着,让我们先来看看 setTimeout
相关基础。
setTimeout()
方法可以设置一个定时器,该定时器在定时器到期后执行一个函数或指定的一段代码。
最简单的示例:
100ms
后弹出系统对话框。(非严谨的,用俚语表述的需求。。。莫怪)
setTimeout(function(){ alert('走位,走位') },100) 复制代码
好简单的,是不?地球人都知道的东西,再写就没意思了。接下来写点可能会不知道的东东。
-
1.函数参数个数
let timer = window.setTimeout(fun[,delay,param1,param2,...]);
我们常用的就两个参数,估计一个参数,或者多于两个参数的情况用的比较少。只有一个参数时,延迟时间默认为0;有多于两个参数时,除开第一和第二参数的其他参数,我们称之为“附加参数”。附加参数都会做为回调函数的参数传递。
let func = function(a,b){ console.log(a+b); } setTimeout(func,100,10,20); //30 复制代码
- 2.用于防抖
防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
function debounce(fn, wait) { var timer = null; return function () { var context = this var args = arguments if (timer) { clearTimeout(timer); timer = null; } timer = setTimeout(function () { fn.apply(context, args) }, wait) } } 复制代码
-
3.轮循任务(setInterval)
js
中可以使用setInterval
开启轮询,但是这种存在一个问题就是执行间隔往往就不是你希望的间隔时间。使用setTimeout
构造轮询能保证每次轮询的间隔。 -
4.程序切片 我们都清楚
js
是单线程的,意味着js处理大数据的时候,容易处于‘假死’状态。那么这个时候,我们可以利用setTimeout
进行切片,来避免‘假死’状态的出现。
let func = function(index){ .... } for(let i=0,l=10000000000;i<l;i++){ (function(index){ setTimeout(function(){func(index)},0) })(i) } 复制代码
基本 setTimeout
常用的用法就是这些。
回手掏(setTimeout原理及javaScript运行机制之event loop)
走位完了,让我们一起回手掏掏他们的原理和机制。
js 单线程
我们都知道,现代浏览器每个标签页就是一个进程,每个进程下面又包含了各种线程,比如 javaScript
线程,渲染线程,请求线程等等。也就是说 js
是单线程的。估计有人要问了为什么 js
是单线程呢,为什么不是多线程呢?其实这和 js
的用途有关系。作为浏览器脚本语言, JavaScript
的主要用途是与用户互动,以及操作 DOM
。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定 JavaScript
同时有两个线程,一个线程在某个 DOM
节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?所以,为了避免复杂性,从一诞生, JavaScript
就是单线程,这已经成了这门语言的核心特征,将来也不会改变。为了利用多核 CPU
的计算能力, HTML5
提出 Web Worker
标准,允许 JavaScript
脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM
。所以,这个新标准并没有改变 JavaScript
单线程的本质。
OK, js
是单线程,那么我们可以得出 setTimeout
绝对不是开启另一个线程来实现异步的。那 setTimeout
是如何达到异步效果的呢?
任务队列
在 js
中,所有任务都分为同步任务和异步任务两大类。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"( task queue
)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
(1)所有同步任务都在主线程上执行,形成一个执行栈( execution context stack
)。
(2)主线程之外,还存在一个"任务队列"( task queue
)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
只要主线程空了,就会去读取"任务队列",这就是 JavaScript
的运行机制。这个过程会不断重复。
"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。
Event loop
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为 Event Loop
(事件循环)。
这里一定要分清楚 task queue
和 Event loop
概念。之前,发现很多人总是分不清楚 task queue
和 Event loop
概念。说 setTimeout
原理时,每每有人说到是将回调函数放入到事件队列里面,然后。。。。。。;真觉的这样的说法不太好。
setTimeout理解
个人推测,每当调用 setTimeout
方法,实际上是向一个缓存对象写入一个键值对(以数字为键,以回调函数为值)。当到达指定延迟时间后,才将回调函数放入到 task queue
中,等待进入执行栈。
独特例子分析
在回手掏完之后,基本上 setTimeout
以及 js
运行机制应该大概明白了。通过以上的原理及机制,我们来分析一下下面的几个例子(包含之前没有说道的 setTimeout
的注意项):
开篇代码解析
setTimeout(function(){console.log(1)},30) setTimeout(function(){console.log(2)},10) setTimeout(function(){console.log(3)},0) let now = new Date(); while(new Date() - now<100){ } console.log(0); 复制代码
这段代码在执行栈中执行顺序为:
now task queue
以上就是整个代码的大概执行流程。因此,我们得到的打印顺序为 0>3>2>1。这个里面主要是要理解,
调用setTimeout方法并不是直接将回调函数放入 task queue
中,而是等到到达指定延时后,才将回调函数放入 task queue
中
。
最大延迟时长
也许你经常用几秒或者几十秒做延迟时间,估计你很少会想到 setTimeout
能设置的最大的延迟时间是多少呢?或者如果超出 setTimeout
的最大延迟时长,又会怎么样?
在一篇文章上看到过, setTimout
最大延迟时长是用32位有符号数存储的,因此他的最大值应该是 Math.pow(2,31)-1=2147483647
,那么换算成天,大约就是 24.8
天。如果设置的时长大于 2147483647
,那么 setTimeout
的延时时长将会自动设置为 0
;
setTimeout(function(){console.log(1)},2147483648) setTimeout(function(){console.log(2)},2147483647) 复制代码
你会看到,控制台会立即输出 1
,而 2
却没有输出,如果上面的结论是正确的,要想看到 2
,估计要等 24.8
天了。嘿嘿,反正我是不准备等的了。。。又想尝试的兄弟,可以试了以后告知下。
延时时长0
在MDN上看到这么一句话,“ delay
取默认值 0
,意味着“马上”执行,或者尽快执行。”
也就是说将延时时长设置为 0
,是在有条件的情况下尽快执行。但真的是 0
毫秒就放入 task queue
中吗?
我们来看段代码:
setTimeout(function(){ console.log(2) },2) setTimeout(function(){ console.log(6) },6) setTimeout(function(){ console.log(1) },1) setTimeout(function(){ console.log(3) },3) setTimeout(function(){ console.log(0) },0) 复制代码
这样的一段代码,可能会有些人认为他的输出结果是: 0>1>2>3>6
.实际情况却不是这样的,实际输出确是 1>0>2>3>6
.
有人解释说,这是因为从执行延时1ms的延时函数,到执行 0ms
的延时函数,中间超过了 1ms
,导致延时 1ms
的回调函数先于延时 0ms
的回调函数进入 task queue
中。但是这种说法真不能苟同,如果这样都需要 1ms
那么 js
的运行效率也太低了。而且可以在 1ms
的延时函数 和 0ms
的延时函数打印时间戳,可以发现,根本不可能是运行超过 1ms
导致的结果。
那么我们将 1ms
的延时函数和 0ms
的延时函数任意交换位置可以发现,谁在前面谁先进入 task queue
。那么可以大胆推论,其实延时 0ms
与延时 1ms
是等价的(这个结论是自我推导的,不一定正确)。因此才有了 1>0>2>3>6
输出顺序。
最小间隔时长
有人会说上面例子输出结果是因为 setTimeout
的最小间隔时长导致的。最小间隔时长,是个很恶心的概念,最初接触的时候没有正确理解,导致一度认为这个最小间隔时长有问题。
我们来看看最小间隔时长在 MDN
上面的解释。在 MDN
上面它不叫“最小间隔时长”,而是叫做“最小延迟时间”。在以前,最小间隔时长通常为 10ms
,现在的现代浏览器通常为 4ms
(根据各个浏览器的不同会有些差异)。一直以来,都被“最小延迟时间”这个名词所误导,总认为延时时长必须大于等于最小延迟时间。但是,各种测试总是实现不了或者验证不了这个“最小延迟时间”。在读 MDN
的时候,发现它有这么一句话"这通常是由于函数嵌套导致(嵌套层级达到一定深度),或者是由于已经执行的 setInterval
的回调函数阻塞导致".
在浏览器中,setTimeout()/setInterval() 的每调用一次定时器的最小间隔是4ms,这通常是由于函数嵌套导致(嵌套层级达到一定深度),或者是由于已经执行的setInterval的回调函数阻塞导致的
这才焕然大悟,原来“最小延迟时间”是有限制条件的,他的限制条件就是函数嵌套到达一定深度,或者setInterval回调阻塞。
那么接下来我们就用一段代码验证下:
function doFunc(count){ console.time('time total:') let timeFunc = function(){ if(count>=0){ setTimeout(timeFunc,0) count --; }else{ console.timeEnd('time total:') } } timeFunc() } doFunc(10) 复制代码
如果没有最小延迟时间的限制,那么在只有这段代码的环境下运行,那么应该会很快运行完。但是在chrome中实际输出确是 33.2451171875ms
。这就直接证明了最小延迟时间的存在,并且触发他的条件是函数嵌套到达了一定深度。
好吧,个人觉的 setTimeout
的小九九也就这些了,没有再写下去的必要了。比如 setTimeout
回调函数中的 this
,怎么清除当前建立的所有 setTimeout
等等。类似这些地球人都知道的事情,估计也不是您看这篇文章的目的了。
走吧,客官们,嗨把刺激战场喽。。。。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Chinese Authoritarianism in the Information Age
Routledge / 2018-2-13 / GBP 115.00
This book examines information and public opinion control by the authoritarian state in response to popular access to information and upgraded political communication channels among the citizens in co......一起来看看 《Chinese Authoritarianism in the Information Age》 这本书的介绍吧!
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
HEX HSV 转换工具
HEX HSV 互换工具