一、理解事件循环(EventLoop)
javeScript是单线程语言,同一时间只能做一件事,并且javeScript要在宿主环境(浏览器/nodejs)中运行,因为浏览器内部有执行js代码的V8引擎。但浏览器是多线程的,用户交互、网络请求、定时器等浏览器中的事件会产生对应的任务,多个任务就需要在任务队列中排队,浏览器的主线程再从任务队列中依次取出任务执行,这个过程不断重复进行形成了一个循环,就是事件循环。
二、执行过程
js中的所有任务都可以分为同步任务和异步任务,异步任务又可以分为宏任务和微任务
执行顺序:
同步任务先进入主栈程,遇到异步任务,交给浏览器来处理(事件被触发之后就进入到任务队列,排队等待执行后续代码),当主线程空闲时,才会从任务队列里取出任务继续执行;异步任务里先执行微任务再执行宏任务
三、微任务和宏任务
1、微任务(js语法)
Promise对象.then()
await下面的代码都放入微任务等待执行
2.宏任务(宿主环境)
script
dom事件
ajax
steTimeout
来段代码感受下:
<script>
console.log(1)
//宏任务
setTimeout(function() {
console.log(2)
}, 0)const p = new Promise((resolve, reject) => {
//这里只是new一个promise对象 里面的内容正常执行
console.log(3)
resolve(1000) // 标记为成功
console.log(4)
})
//.then之后的内容才被加入到微任务里面
p.then(data => {
console.log(data)
})console.log(5)
</script>
//1 3 4 5 1000 2
难度升级版:
<script>
console.log(1);
async function fnOne() {
console.log(2);
await fnTwo(); // await调用函数正常执行, 然后等待
console.log(3); //await后面的代码放入微任务
}
async function fnTwo() {
console.log(4);
}
fnOne();
//加入宏任务 但过2秒才执行 在下面定时器的后面执行
setTimeout(() => {
console.log(5);
}, 2000);
let p = new Promise((resolve, reject) => {
// new Promise()里的函数体会马上执行所有代码
console.log(6);
resolve();
console.log(7);
})
//加入宏任务
setTimeout(() => {
console.log(8)
}, 0)
//promise.then之后的内容才加入微任务
p.then(() => {
console.log(9);
})
console.log(10);
</script><script>
console.log(11);
//整个定时器都加入宏任务
setTimeout(() => {
console.log(12);
let p = new Promise((resolve) => {
resolve(13);
})
//promise.then加入微任务
p.then(res => {
console.log(res);
})
console.log(15);
}, 0)
console.log(14);
</script>//第一个script标签里面的内容走完,立即去执行微任务
//微任务清空再执行下一个script,再清空微任务,最后找排队中的宏任务
//1 2 4 6 7 10 3 9 11 14 8 12 15 13 5