js事件循环(Event Loop)
本文于 388 天之前发表,文中内容可能已经过时。
微任务和宏任务皆为异步任务,它们都属于一个队列,主要区别在于他们的执行顺序,Event Loop的走向和取值。
Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
- 同步任务(Synchronous Task):立即执行,先入先出。
- 异步任务(Asynchronous Task):不会立即执行,而是放入任务队列,等待事件循环调度。
1、宏任务和微任务的区别
1 | 宏任务 浏览器 Node |
宏任务与微任务之间的执行顺序(宏任务(整个js)->同步任务->微任务->宏任务(下一个))
1 | setTimeout (() => { console.log(4)}) // 宏任务 |
下面说说执行到宏任务后是怎么继续运行的
(这里声明下,整段js代码就是第一个大的宏任务,事件循环是由这第一个宏任务开始的,然后分出微任务,这里是为了理解微任务宏任务的执行区别就先跳过这第一层)
2、事件循环中的执行顺序示意
- 执行同步任务,进入调用栈(Call Stack)。
- 同步任务执行完后:
- 将异步任务(宏任务)加入 宏任务队列
- 将产生的微任务加入 微任务队列
- 当前宏任务执行结束后:
- 立即执行所有 微任务队列(直到队列清空)
- 清空微任务后,如果有新的宏任务:
- 取下一个宏任务执行
- 重复上述循环。
3、举例说明执行顺序
1 | console.log('1'); |
执行步骤:
进入主脚本(这是一个宏任务),执行同步代码:
- 输出
'script start' - 注册
setTimeout→ 放入宏任务队列 - 注册
Promise.then→ 放入微任务队列 - 输出
'script end'
- 输出
当前宏任务(整个脚本)执行完毕 → 清空
微任务队列:
- 输出
'Promise'
- 输出
进入下一个宏任务:
- 执行
setTimeout回调 → 输出'setTimeout'
- 执行
2、场景
去银行办存钱业务,先取号再排队。 “您的号码为XX,前边还有XX人。”
银行柜台前排着一条队伍,都是存钱的人,存钱属于宏任务,这条队伍就是宏任务队列。
当一个“大爷”被叫到了自己的号码,就上前去–被处理,处理存钱业务时,‘宏大爷’突然想给自己的存款办个微理财(微任务),那么银行职员就将他的需求添加到自己的微任务队列,大爷就不用再排队了,直接在存钱宏任务进行完后就处理衍生出来的微任务理财,办理财时大爷又说办个信用卡,那就又排到微任务队列里。当大爷的微任务(办理理财和办信用卡)没有办理完,是不会让让下一个人办理业务的**(即微任务没执行完是不会执行下一个宏任务的)**。
但要是在此次存钱时‘宏大爷’说他还要存钱,且是他老伴要存钱,也是宏任务,但不好意思,需要取号到宏任务队列的后面排队(这里就是在宏任务进行时产生微任务和宏任务的处理方式)。

3、案例
结合下面的题目理解理解(这里先不介绍node环境的事件循环的特殊地方,主要以浏览器环境):
1 | <script> |
