一、进程与线程
进程 描述了 CPU 在运行指令及加载和保存上下文所需的时间,放在应用上来说就代表了一个程序。
线程 是进程中的更小单位,描述了执行一段指令所需的时间。
一个进程可以有多个线程。
JS 是单线程执行的
在 JS 运行的时候可能会阻止 UI 渲染,这说明了 JS 引擎线程和渲染线程两个线程是互斥的。
二、执行栈
可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。
当我们执行 JS 代码的时候其实就是往执行栈中放入函数
三、浏览器中的 Event Loop
当遇到异步的代码时,会被挂起并在需要执行的时候加入到 Task(有多种 Task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,所以本质上来说 JS 中的异步还是同步行为。
不同的任务源会被分配到不同的 Task 队列中,任务源可以分为** 微任务** (microtask) 和 ** 宏任务** (macrotask)。
微任务包括 process.nextTick ,promise ,MutationObserver。
宏任务包括 script , **setTimeout ,setInterval **,setImmediate ,I/O ,UI rendering。
Event Loop 执行顺序如下所示:
- 首先执行同步代码,这属于宏任务
- 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 当执行完所有微任务后,如有必要会渲染页面
- 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数