什么是 event loop
event loop
也叫事件循环 || 事件轮询
是浏览器或Node
解决单线程运行时不会阻塞的一种机制
- JS 是单线程运行的
- 异步要基于回调(
callback
) 来实现 event loop
就算异步回调的实现机制 || 实现原理
JS 如何执行
这里是废话,但有助于后面理解
- 从前到后,一行一行执行
- 如果某一行执行报错,则停止下面代码的执行
- 先把同步代码执行完,再执行异步
乙:那怎么先把同步执行完,再执行异步?
甲:是通过回调来实现
乙:回调又怎么去实现?
甲:那这就是 event loop
的机制
这上面三条全是废话,但这算是接下来讲解的铺垫或者是基础
示例
console.log('Hi');
setTimeout(function cb1() {
console.log('cb1'); // cb 即 callback
},2000)
console.log('Bye');
- Browser console: 模拟浏览器控制台界面
- Call Stact: 调用栈
- Web APIs
:浏览器运行环境
API的一个定义 比如说
setTimeout再本身的es(
ECMAScript`)里面是没有的,这些东西是再浏览器的规范里面有的 - Event Loop:事件轮询 || 事件循环
- Callback Queue : 回调函数的队列 Empty 表示没有
1. 执行第一行代码
console.log('Hi');
执行完后会清空调用栈,执行完的结果会直接显示在Browser console 里
2. 执行第二行代码
setTimeout(function cb1() {
console.log('cb1'); // cb 即 callback
},2000)
当执行到 setTimeout 的时候 浏览器把这个函数放到了 定时器里面 定时器的定时是2000毫秒,2秒钟后把这个 cb1 放到Callback Queue 里面,然后结束后清空调用栈,这一步console.log不会打印任何东西,因为2秒还没走完,还在Web API 里面
3. 执行最后一行代码
console.log('Bye');
执行完之后 调用栈清空 这个时候 timer 还在Web APIs 中 因为从开头到最后 执行时间太短了,根本不够2秒钟
分析
console.log('Hi');
setTimeout(function cb1() {
console.log('cb1'); // cb 即 callback
},2000)
console.log('Bye');
这个时候第一行跟最后一行都执行完了,也就是同步代码都执行完了,Call Stack 空了,没有任何代码能放到Call Stack 里去执行了,就会立刻启动 Event Loop 事件循环机制,当然,这个是浏览器内核启动的,不是我们启动的
这个机制是干什么的呢?
Event Loop 会一遍一遍的去做这个循环,会到 Callback Queue 异步函数回调里面去找,找到了就拿到Event Loop 里面去 然后放到Call Stact 里去执行
4. 等到2s之后,时机触发了
Event Loop 会立马拿到 cb1 这个函数 然后放到Call Stack 里面
然而因为 cb1 函数里面有函数体,所以会定义到console.log('cb1');
这一行 然后再去执行,就会打印cb1 然后清空Call Stack 调用栈
到目前位置,整个代码执行完毕,这就是整个 Event Loop 的整个执行过程
示例2
<button id="btn">提交</button>
<script>
console.log('Hi');
btn.onclick = function() {
console.log('button clicked');
}
console.log('Bye');
</script>
DOM 事件 和 Event Loop 的区别
区别在于触发的时机不一样,setTimeout 是指定时间后触发 而 click 是用户什么时候点击什么时候触发,和用户交互有关系
这里就不做过多的演示了
1. 首先同步代码先走完
当用户点击的时候,浏览器会立马把Web APIs 里面的回调函数放到 Callback Queue 里面去,然后根据Event Loop 的机制 立马放到 Call Stack 里去执行
DOM 事件和 Event Loop
所以说 DOM事件和Event Loop 也是有很强的关联性的,DOM事件也是基于Event Loop 来实现的
- JS 是单线程的
- 异步(setTimeout,ajax 等) 使用回调,基于 Event Loop
- DOM 事件也使用回调,基于 Event Loop
DOM事件 只是基于Event Loop 来实现的 但它不是异步
总结
- 同步代码,一行一行放到 Call Stack 执行
- 遇到异步,会先 "记录" 下,等待时机(定时,网路请求等)
- 时机到了,就移动到 Callback Queue 里面
- 如果 Call Stack 为空(即同步代码执行完)Event Loop 开始工作
- 轮询查找 Callback Queue ,如果有则移动到 Call Stack 执行
- 然后继续轮询查找(永动机一样)