EventLoop又叫事件循环,用来控制浏览器中事件的执行过程。javascript
以下图所示,浏览器存在执行栈(单线程执行JS代码)、任务队列及一些WEB API。java
在浏览器中运行以下代码:promise
console.log(1);
setTimeout(function(){
console.log(2);
}, 5000);
console.log(3);
// 输出:
// 1
// 3
// 2
复制代码
执行过程以下(演示地址):浏览器
console.log
,输出1setTimeout
,启动定时器console.log
,输出3console.log
,输出2理解了这个执行过程,就能明白为何下面代码(setTimeout时间设为0)的输出结果与上面相同:异步
console.log(1);
setTimeout(function(){
console.log(2);
}, 0);
console.log(3);
// 输出:
// 1
// 3
// 2
复制代码
执行过程:oop
console.log
,输出1setTimeout
,启动定时器console.log
,输出3console.log
,输出2并非全部异步任务的执行优先级都相同,微任务(microtask)比宏任务(macrotask)要优先执行。post
在浏览器环境中,常见的宏任务有setTimeout
、MessageChannel
、postMessage
、setImmediate
;常见的微任务有MutationObsever
和Promise.then
。ui
从下面这段代码来看浏览器的执行过程:spa
setTimeout(() => {
console.log('timeout1');
Promise.resolve().then(() => {
console.log('promise1');
});
Promise.resolve().then(() => {
console.log('promise2');
});
}, 0);
setTimeout(() => {
console.log('timeout2');
Promise.resolve().then(() => {
console.log('promise3')
});
}, 0);
// 输出:
// timeout1
// promise1
// promise2
// timeout2
// promise3
复制代码
如下为详细执行过程:.net
setTimeout
,启动定时器1
定时器1
时间到,将回调T1
放入宏任务队列
setTimeout
,启动定时器2
定时器2
时间到,将回调T2
放入宏任务队列
回调T1
,放入执行栈
console.log
,输出timeout1
Promise.then
,将回调P1
放入微任务队列
Promise.then
,将回调P2
放入微任务队列
回调P1
,放入执行栈
console.log
,输出promise1
回调P2
,放入执行栈
console.log
,输出promise2
回调T2
,放入执行栈
console.log
,输出timeout2
Promise.then
,将回调P3
放入微任务队列
回调P3
,放入执行栈
console.log
,输出promise3
参考资料: