以面试常见代码题目为例:1
2
3
4
5
6
7
8
9
10
11
12
setTimeout(function(){console.log(4)},0);
new Promise(function(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 2 3 5 4
关键词:
事件循环(event loop):一个
任务队列(task queue):多个,主要是下面这俩
宏任务macrotask:script(整体代码) setTimeout setInterval setImmediate I/O UIrendering
微任务microtask:process.nextTick Promise.then MutationObserver
任务源(task source):每个任务都有,相同任务源放入同一个任务队列
备注:点击事件等属于I/O;UIrendering是在DOM变化时执行,大约16ms调用一次;关于setImmmediate和process.nextTick,为node.js中的方法;关于tick——
事件循环:主线程不断从任务队列中读取事件。
每一次事件循环中,macrotask只会提取一个执行,而microtask会一直提取,直到队列空。接着继续提取一个macrotask中的任务,再执行完microtask中的任务。如此循环。
故上述代码大致顺序为:
1、整个script推入macrotask中,遇见setTimeout挂起到新的macrotask中,遇见promise.then挂起到microtask中;
2、script的macrotask执行完后,输出1 2 3(注意promise自身中的是在script部分执行),接着执行完microtask中的所有事件,输出5;
3、读取任务队列,此处为setTimeout的事件,输出4;所有队列均清空。
异步任务 回调函数 执行栈 任务队列 主线程:
将正常任务扔到主线程的执行栈中执行,异步任务扔到任务队列(事件)中。执行栈执行完后,任务队列中的事件进入执行栈,回调函数开始执行。
若涉及定时器,主线程会检查后确认任务队列相应任务是否进入主线程。
参考网站:http://www.ruanyifeng.com/blog/2014/10/event-loop.html