执行顺序
1 | setTimeout(function(){ |
js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
setTimeout
1 | setTimeout(() => { |
控制台执行task()需要的时间远远超过3秒,说好的延时三秒,为啥现在需要这么长时间啊?
执行过程:
1、task()进入Event Table并注册,计时开始。
2、执行sleep函数,很慢,非常慢,计时仍在继续。
3、3秒到了,计时事件timeout完成,task()进入Event Queue,但是sleep也太慢了吧,还没执行完,只好等着。
4、sleep终于执行完了,task()终于从Event Queue进入了主线程执行。
setTimeout(fn,0)这样的代码的意思是:只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行。
setInterval
唯一需要注意的一点是,对于setInterval(fn,ms)来说,我们已经知道不是每过ms秒会执行一次fn,而是每过ms秒,会有fn进入Event Queue。
一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了。
Promise与process.nextTick(callback)
process.nextTick(callback)
类似node.js版的”setTimeout”,在事件循环的下一次循环中调用 callback 回调函数。
我们进入正题,除了广义的同步任务和异步任务,我们对任务有更精细的定义:
macro-task(宏任务):包括整体代码setTimeout、setInterval、setImmediate、I/O、UI交互事件
micro-task(微任务):Promise、process.nextTick、MutaionObserver
事件循环的顺序:宏任务的Queue → 微任务的Queue → 宏任务的Queue → 微任务的Queue
当时间小于4ms的时候会重置为4ms,当为0或者1ms的时候会当成一个定时器执行!!!
1 | setTimeout(function() { |
1、这段代码作为宏任务,进入主线程。
2、先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
3、接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue。
4、遇到console.log(),立即执行。
5、好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
6、ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。
7、结束。
练习
1 | console.log('1'); |