Js中的事件循环机制EventLoop
在JavaScript代码自上而下执行过程中,分为同步任务和异步任务,异步任务又分为异步微任务和异步宏任务,同步任务也是宏任务。
- 【常见的异步微任务】
- promise
- async/await
- requestAnimationFrame
- 【常见的异步宏任务】
- 定时器setTimeout
- ajax(HTTP网络请求)
- 事件绑定
- …
在主线程自上而下执行js代码时,同步宏任务会优先执行,如果遇到上述异步任务,不会立即执行,而是把这些异步任务存放到EventQueue任务队列中进行排队等待,主线程中的同步任务继续向下执行
当所有同步任务执行完成后,再优先执行所有异步微任务,待所有异步微任务执行完成后,最后再执行异步宏任务
- 在执行过程中会严格按照该顺序执行
- 即使在同步任务没有执行完,但异步任务中已经有到达执行条件了,那也不能执行,必须要等待同步任务执行完成
- 不管什么时候放置的微任务,也不管异步宏任务是否已经到达执行条件了,只要异步微任务存在,就永远不会执行异步宏任务
事件循环机制EventLoop:主线程自上而下,已经执行完所有同步任务,主线程空闲下来,开始到EventQueue任务队列中找异步任务(优先查找微任务),找到任务后拿到主线程中执行,此时主线程又被占用不能处理其他事情,当这个异步任务执行完,主线程又空闲,继续到EventQueue中查找其它异步任务执行,这就是事件循环机制。
关于同步异步的一些面试题
let body = document.body;
body.addEventListener('click', function(){
Promise.resolve().then(() => {
console.log(1);
});
console.log(2);
});
body.addEventListener('click', function(){
Promise.resolve().then(() => {
console.log(3);
});
console.log(4);
});
//答案:2 1 4 3
//======================================================================
console.log('start');
let intervalId;
Promise.resolve().then(() => {
console.log('p1');
}).then(() => {
console.log('p2');
});
setTimeout(() => {
Promise.resolve().then(() => {
console.log('p3');
}).then(() => {
console.log('p4');
});
intervalId = setInterval(() => {
console.log('interval');
}, 3000);
console.log('timeout1');
}, 0);
//答案:start p1 p2 timeout1 p3 p4 interval....
//======================================================================
setTimeout(() => {
console.log('a');
});
Promise.resolve().then(() => {
console.log('b');
}).then(() => {
return Promise.resolve('c').then(data => {
setTimeout(() => {
console.log('d')
});
console.log('f');
return data;
});
}).then(data => {
console.log(data);
});
//答案:b f c a d
//======================================================================
function func1() {
console.log('func1 start');
return new Promise(resolve => {
resolve('OK');
});
}
function func2() {
console.log('func2 start');
return new Promise(resolve => {
setTimeout(() => {
resolve('OK');
}, 10);
});
}
console.log(1);
setTimeout(async () => {
console.log(2);
await func1();
console.log(3);
}, 20);
for (let i = 0; i < 90000000; i++) {} //循环完大于80ms左右
console.log(4);
func1().then(result => {
console.log(5);
});
func2().then(result => {
console.log(6);
});
setTimeout(() => {
console.log(7);
}, 0);
console.log(8);
//答案:1 4 [func1 start] [func2 start] 8 5 2 [func1 start] 3 7 6
//======================================================================
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
console.log(4);
console.time('AA');
for (let i = 0; i < 90000000; i++) {
// do soming
}
console.timeEnd('AA'); //=>AA: 79ms 左右
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
//答案:2 4 [AA:79ms] 5 7 9 3 1 6 8
//======================================================================
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
//答案:[script start] [async1 start] async2 promise1 [script end] [async1 end] prmise2 setTimeout