JS、浏览器——栈和队列(事件循环相关)
调用栈(Call Stack):这是一个栈(LIFO,后进先出)结构,记录当前正在执行的函数。它属于执行上下文管理知识。
任务队列(Task Queue):这是一个队列(FIFO,先进先出)结构,存放等待执行的回调函数。它属于调度策略知识。
它们共同组成了事件循环的两个核心角色:“栈”负责当前做什么,“队列”负责接下来要做什么。
在这里,我们只学习栈和队列的相关内容,涉及到事件循环的知识可移步我的另一篇文章【浏览器——事件循环】
一、js引擎执行代码过程
引擎先执行所有同步代码(填满并清空调用栈)。
遇到异步API(如
setTimeout、fetch),引擎不等待,直接交给Web APIs(浏览器提供)去处理(处理后的回调函数会放在队列中,等待调用),自己继续执行后续代码。当调用栈完全清空后,事件循环才会从任务队列中取出回调函数,压入调用栈执行。
二、任务队列
任务队列包含两类:微任务队列和宏任务队列。
宏任务:由宿主环境(浏览器/Node)发起的任务
微任务:由 JS 引擎自身发起的任务,优先级高于宏任务
| 宏任务 | 微任务 |
UI 渲染
... |
... |
三、执行机制
记住这句口诀:“一个宏任务,一筐微任务”。
在每一轮事件循环中,执行机制是这样的:
- 从宏任务队列中取出一个最旧的任务执行。
- 执行完毕后,检查微任务队列。
- 清空(执行完)微任务队列中的所有任务。
- 进入下一轮循环,再取下一个宏任务。
关键点:微任务会在下一个宏任务开始之前全部执行完毕。
