Event Loop
即事件循环,是指浏览器或Node
的一种解决javaScript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
JavaScript代码的执行过程中,除了依靠函数调用栈来搞定函数的执行顺序外,还依靠任务队列(task queue)(先进先出)来搞定另外一些代码的执行
Javascript
单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行(代码从上到下的执行),异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
一个线程中,事件循环是唯一的,但是任务队列可以拥有多个。
任务队列又分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为task与jobs。
macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task大概包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)
setTimeout/Promise等我们称之为任务源。而进入任务队列的是他们指定的具体执行任务。
来自不同任务源的任务会进入到不同的任务队列。其中setTimeout与setInterval是同源的。
事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始第一次循环(即宏任务)。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的micro-task(微任务)。当所有可执行的micro-task(微任务)执行完毕之后。循环再次从macro-task(宏任务)开始,找到其中一个任务队列执行完毕,然后再执行所有的micro-task(微任务),这样一直循环下去。
一个简单的例子:
setTimeout(function(){
console.log('timeout1');
})
new Promise(function(resolve){
console.log('promise1');
for(var i =0; i <1000; i++) {
i ==99&& resolve();
}
console.log('promise2');
}).then(function(){
console.log('then1');
})
console.log('global1')
//打印的顺序
// promise1
// promise2
// global1
// then1timeout1
具体可以参考:https://www.jianshu.com/p/6a1932dbbc95 https://zhuanlan.zhihu.com/p/55511602 这二篇文章