event loop过程
- 同步代码,一行一行放在Call Stack执行
- 遇到异步先记录下来,等待时机(定时,网络请求)
- 时机一到立马推入Callback Queue中
- 如Call Stack为空(同步代码执行完毕),Event Loop开始工作
- 轮询查找Callback Quque,有则移动到Call Stack中执行
- 然后继续轮询查找
例1
console.log(100)
setTimeout(() => {
console.log(200)
}, 5000);
console.log(300)
// 输出
// 100
// 300
// 200
代码依次执行,遇到setTimeout为异步任务,先记录下来,等待时机,5秒后推入Callback Queue队列中,Call Stack清空后,Event Loop开始工作,将Callback Queue中的任务依次推入Call Stack中执行。
例2
console.log(100)
setTimeout(() => {
console.log(200)
}, 0);
Promise.resolve().then(()=> {
console.log(300);
})
console.log(400)
// 输出
// 100
// 400
// 300
// 200
拓展例1的代码,加入promise,执行顺序就会有变化。先讲两个概念,宏任务和微任务,
宏任务:定时器,事件绑定,ajax
定时器:Promise,process.nextTick(nodejs)
宏任务和微任务的执行顺序
在Call Stack中不仅会形成宏任务队列,还会形成微任务队列,在每一次Call Stack清空后都需要将微任务队列清空(全部执行)。
for (macTask in macTaskList) {
// 循环执行Callback Queue队列中的宏任务
...
for (micTaks in micTaskList) {
// 循环执行当前宏任务中的微任务
...
}
}
宏任务、微任务、Dom渲染的关系
如图
执行顺序
- Call Stack清空
- 执行当前的微任务
- 尝试DOM渲染
- 触发Event Loop
微任务和宏任务的区别
- 宏任务:DOM渲染后触发,由浏览器规定(Web APIs)
- 微任务:DOM渲染前执行,微任务是ES6语法规定
event loop和Dom渲染
- 每次Call Stack清空(即每次轮询结束),即同步任务执行完
- 都是Dom重写渲染的机会,Dom结构如有改变则重新渲染
- 然后再去触发下一次Event Loop
微任务和宏任务之间存在dom渲染
const main = document.getElementById('main');
const frg = document.createDocumentFragment();
for(let i = 0; i < 10; i++) {
const li = document.createElement('li');
li.innerHTML = i;
frg.appendChild(li);
}
main.appendChild(frg);
new Promise((resolve) => {
resolve();
}).then(() => {
console.log('微任务已经执行');
alert('dom 还未插入')
});
setTimeout(() => {
console.log('宏任务执行');
alert('dom 已经插入')
});
经典面试题
async function asycn1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeout ');
}, 0);
asycn1();
new Promise((resolve) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('script end');
执行顺序?可留言回复