本文总结一下前端面试重难点,事件轮循机制。
JS引擎常驻于内存中,等待宿主(浏览器/node)将js代码或函数传递给它执行,如何传递,这就是事件循环所做的事情,当js执行栈空闲时,事件循环机制会从任务列表中提取第一个任务进入执行栈执行,优先提取微任务,待微任务队列清空后,再提取宏任务,并不断重复该过程。
首先我们要对宏任务和微任务进行了解。(!important)
常见宏任务
主代码块
setTimeout/setInterval
ajax
I/O
UI渲染
常见微任务
Promise
process.nextTick
Object.observe
JS单线程任务从时间上分为同步任务和异步任务,而异步任务又分为宏任务和微任务。
在执行代码之前,任务队列是空的,所以优先执行主代码块,过程中,遇到同步任务则立即将任务放到调用栈执行任务,遇到宏任务则将任务放到宏任务队列,遇到微任务则放到微任务队列。
主线程任务执行完后,先检查微任务队列是否有任务,有的话则按照先入先出的顺序将先放进来的微任务放入调用栈中执行,并将该任务从微任务队列中移除,直到把所有为微任务清空时,查看宏任务队列,有的话则按照先进先出的顺序执行,将任务放入调用栈并将该任务从宏任务队列中移除,这一个任务执行后继续查看微任务队列,有任务执行微任务队列,没任务继续执行宏任务队列的任务。
例题
setTimeout(() => {
console.log('setTimeout');
}, 0);
async function async2() {
console.log('async2 end');
}
async function async1() {
await async2();
console.log('async1 end');
}
async1();
console.log('start');
new Promise(resolve => {
console.log('p');
resolve();
}).then(function () {
console.log('p1');
}).then(function () {
console.log('p2');
})
//async2 end => start => p => async1 end => p1 => p2 =>setTimeout
记住三点;
1,async里的await fn() 也是同步 因为await后的是微任务;
2,promise内的代码是同步,只有.then后的才是微任务
3,先微任务,后执行宏任务。
有关于事件轮循的任何问题欢迎评论区讨论!