老实说,写这篇文章的时候内心是有点压抑的,由于受到打击了,为何?就 由于喜欢折腾不当心看到了这个"简单"的函数:javascript
macro-task包括:script(总体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。java
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserverpromise
在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,因而就有了这个:spa
(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中获得的看法吧,有啥不对之处望指正:另外,参考了一下别人的文章:https://zhuanlan.zhihu.com/p/26238030写的确实不错