js事件循环
事件循环是js处理异步函数的具体方法
具体做法是:
1.执行 执行栈中的代码;
2.遇到一些特殊的代码交给浏览器的其他线程处理;
3.将执行栈中的代码全部执行完毕
4.从事件队列中取出第一个任务放入执行栈,然后重复第一步;
事件队列在不同的宿主环境中有所差异,大部分宿主环境会将事件队列进行细分,在浏览器中,事件队列分为两种:
1.宏任务(队列) : macroTask,计时器结束的回调,事件回调,http回调等等绝大部分异步函数进入宏队列;
2.微任务(队列) : microTask, Promise.then, MutationObserver
当执行栈清空时,js引擎首先会将微任务中的所有任务依次执行结束,如果没有微任务,则执行宏任务;
案例1 执行过程
setTimeout(function func1(){
console.log('abcd')
},0)
for(var i = 0 ; i < 10000; i++){
console.log(i);
}
执行过程:
1. 首先执行全局代码,**创建一个执行栈,**新建全局上下文,然后执行代码,创建一个setTimeout
上下文,然后setTimeout
内部通知宿主其他线程,开始计时
2. 计时完成后,把其其他线程里边的执行的函数func1
放进事件队列中进行排队,等待执行栈清空后才可以执行事件队列中的任务
3. 然后把执行栈中的setTimeout
上下文销毁,继续执行下边的代码for循环,创建console.log
执行上下文,然后执行代码,输出结果(0-9999),执行结束后,销毁console.log
上下文,没有全局代码了,销毁全局上下文,此时执行栈为空
4. 然后把事件队列中的函数func1
拿出来放进执行栈中,执行func1
,最后输出结果abc
5. 执行结果顺序为 (0-9999),abc
案例2 执行过程和上边类似
setTimeout(function func1(){
console.log(1);
a();
},0)
function a(){
setTimeout(function func2(){
console.log(2)
},0)
console.log(3)
}
a();
console.log(4)
//执行结果
3 4 1 3 2 2
案例3 执行过程类似
//事件也是其他线程监听,
//加入某个人手速特别快,在i=100时点击了按钮,此时会把func1放进宿主的其他线程,然后在放进队列中排队,等待全局上下文中执行完毕后输出(0-999),才会执行队列中的任务,输出a
//无论手速多块都会最后执行输出a
<button id="btn"> 点我</button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function func1() {
console.log("a")
}
for(var i = 0 ; i < 1000; i++){
console.log(i)
}
</script>
//执行结果