老实说,写这篇文章的时候心里是有点压抑的,因为受到打击了,为什么?就 因为喜欢折腾不小心看到了这个"简单"的函数:
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, i * 1000); } console.log(i);
什么?这不就是我很久之前看到的先打印一个5,再打印一个5,之后每隔一秒就打印一个5,直到打印完6个5的实现方法吗?那么问题来了,如果我要依次打印0,1,2,3,4,5的话我该怎么办,其实在这之前我就知道有这两个方法:一个是这样:
function log(i){ setTimeout(function(){ console.log(i) },i*1000) }; for (var i = 0; i < 5; i++) { log(i) ; } console.log(i);
还有一个是这样:
for(var i=0;i<5;i++){ (function(e){ setTimeout(function(){ console.log(e) },i*1000); })(i); }; console.log(i);
不怕笑话,在这之前我是没搞懂这两个函数真正意义上的作用是用来干嘛的,只强迫自己这样记住这样修改就可以了,但是现在不行啊,我有强迫症啊!于是,我慢慢分析了一下,发现上面那段代码可以分离成这样:
i=0时;满足条件;
setTimeout(function(){ console.log(i) },0*1000);
i=1时;满足条件;
setTimeout(function(){ console.log(i) },1*1000);
i=2时;满足条件;
setTimeout(function(){ console.log(i) },2*1000);
i=3时;满足条件;
setTimeout(function(){ console.log(i) },3*1000);
i=4时;满足条件;
setTimeout(function(){ console.log(i) },4*1000);
i=5时,不满足条件,跳出循环,接着执行for循环后面的console.log(i),打印5;最后依次每秒打印5;
真有意思,为什么setTimeout里面的console.log会是后于for循环外面的console.log执行呢?直到我认识到了这个单词=>"队列", 队列又有宏任务队列(Macro Task)以及微任务队列(Micro Task)之分 ,在javascript中:
macro-task包括:script(整体代码), setTimeout , setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises , Object.observe, MutationObserver
上面函数的setTimeout就属于宏任务
在js中,事件循环的顺序是从script开始第一次循环,随后全局上下文进入函数调用栈,碰到macro-task就将其交给处理它的模块处理完之后将回调函数放进macro-task的队列之中,碰到micro-task也是将其回调函数放进micro-task的队列之中。直到函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。 当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列 ,执行完之后再执行所有的micro-task,就这样一直循环。
这就是为什么setTimeout里面的console.log会是后于for循环外面的console.log执行,在函数执行上下文中,seiTimeout函数会被放到处理他的macro-task的队列之中,所以循环的时候setTimeout里面的function是不会被执行的,而是等到所有整体代码(非队列)跑完之后才会执行队列中的函数;写到这里,可能会有点懵逼,其实我也有点懵逼,哈哈哈!!
为了加深理解,还可以试试在里面加入Promise,于是就有了这个:
(function copy() { setTimeout(function() {console.log(4)}, 0); new Promise(function executor(resolve) { console.log(1); for( var i=0 ; i<10000 ; i++ ) { i == 9999 && resolve(); } console.log(2); }).then(function() { console.log(5); }); console.log(3); })()
解释一下=>
1.首先,script任务源先执行,全局上下文入栈。
2.script任务源的代码在执行时遇到setTimeout,作为一个macro-task,将其回调函数放入自己的队列之中。
3.script任务源的代码在执行时遇到Promise实例。Promise构造函数中的第一个参数是在当前任务直接执行不会被放入队列之中,因此此时输出 1 。
4.在for循环里面遇到resolve函数,函数入栈执行之后出栈,此时Promise的状态变成Fulfilled。代码接着执行遇到console.log(2),输出2。
5.接着执行,代码遇到then方法,其回调函数作为micro-task入栈,进入Promise的任务队列之中,此时Promise的then 里面的function回调函数跟setTimeout里面的function回调函数有着异曲同工之意,都会被放到各自的任务队列中,
直到函数上下文即script中所有的非队列代码执行完毕后再执行,而且微任务队列优先于宏任务队列被处理,
总体顺序为:上下文非队列代码>微任务队列回调函数代码>宏任务队列回调函数代码
6.代码接着执行,此时遇到console.log(3),输出3。
7.输出3之后第一个宏任务script的代码执行完毕,这时候开始开始执行所有在队列之中的micro-task。then的回调函数入栈执行完毕之后出栈,这时候输出5
8.这时候所有的micro-task执行完毕,第一轮循环结束。第二轮循环从setTimeout的任务队列开始,setTimeout的回调函数入栈执行完毕之后出栈,此时输出4。
最后,为了加深理解,再上一段代码:
console.log('golb1'); setTimeout(function() { console.log('timeout1'); new Promise(function(resolve) { console.log('timeout1_promise'); resolve(); setTimeout(function(){ console.log('time_timeout') }); }).then(function() { console.log('timeout1_then') }) setTimeout(function() { console.log('timeout1_timeout1'); }); }) new Promise(function(resolve) { console.log('glob1_promise'); resolve(); setTimeout(function(){ console.log('prp_timeout') }); }).then(function() { console.log('glob1_then') })
如果你的执行结果是:golb1=>glob1_promise=>glob1_then=>timeout1=>timeout1_promise=>timeout1_then=>prp_timeout=>time_timeout=>timeout1_timeout1,
可能异步队列算是入门了吧!~~上面的代码看起来有点杂乱,可能用asyns搭配await改造一下会更好,但是这或多或少是鄙人从setTimeout中得到的见解吧
总结
以上所述是小编给大家介绍的从setTimeout看js函数执行过程,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]