Javascript 是单线程的,同一事件只能处理一个任务 Javascript 通过 Event Loop(事件循环)防止主线程阻塞

runtime

111.png

Javascript 运行组成

  1. Javascript Engine。Chrome 的引擎是 V8
  2. Web APIs。DOM、AJAX、Timeout 都是通过调用 Web APIs 实现的
  3. Callback Queue,回调队列。即 Web APIs 中的回调函数,都是在回调队列中排队等待运行的
  4. EventLoop,事件循环。宏任务和微任务的容器


Call Stack

调用栈 调用栈时存放执行的重要条件。因为只有一个调用栈,所以 Javascript 是单线程的

* 追踪函数执行流的机制。当执行环境中调用多个函数时,通过调用栈可以追踪到具体哪一个函数在执行,执行的函数体中又调用了哪些函数
* 每调用一个函数,解释器就会把该函数添加进调用栈并开始执行
* 正在调用栈中执行的函数还调用了其他函数,那么被调用的函数也会被添加进调用栈,一旦这个函数被调用,便会立即执行
* 当前函数执行完毕后,解释器将其清出调用栈,继续执行当前执行环境下的剩余代码
* 当分配的调用栈空间被占满时,会引发“堆栈溢出”

Callback Queue

回调队列

* 在 Javascript 的编译阶段,将一些事件放置在执行队列中

EventLoop

事件循环 Javascript 处理任务是在等待任务、执行任务、休眠等待新任务中不断循环的,这种机制称为事件循环

* 将 Callback Queue 队列中等待执行的事件,放到 Call Stack 中执行

同步任务

* 按照顺序依次执行

微观任务


* 微观任务不属于事件循环,它是 V8 引擎的一个实现,用来实现 Promise 的 then/reject 或其他一些需要同步延后的 callback。本质是哪个

异步任务

异步任务分为 宏任务 和 微任务


宏任务 Macro

参与了事件循环的异步任务

微任务 Micro

没有参与事件循环的”异步”任务 本质:直接在 Javascript 引擎中执行的、没有参与事件循环的任务

* 是一个存在内存回收的任务
* 是一个普通的回调 Callable
* 在当前 Javascript 调用执行完毕后立刻执行的,是同步的
* 微观任务不属于事件循环,它是 V8 引擎的一个实现,用来实现 Promise 的 then/reject 或其他一些需要同步延后的回调
* 本质上它和当前的 V8 调用栈是同步执行的,只是放到了最后面
* 除了 Promise / MutationObserver,在 Javascript 中发起的请求也会创建一个微观任务延后执行

常见异步任务分类

任务 Chrome Node 类别
I/O 宏任务 Marco
reuqestAnimationFrame ×
setTimeout
setInterval
setImmediate ×
process.nextTick × 微任务 Micro
MutationObserver ×
Promise

* requestAnimationFrame 是一个浏览器用于定时循环操作的接口,类似 setTimeout。主要用途是按帧对网页进行重绘
* process.nextTick 是 Node 提供的一个异步执行函数。执行顺序早于 setTimeout 和 setInterval。在主逻辑的末尾任务队列调用之前执行
* MutationObserver 提供了监视 DOM 树变化的能力

优先级

* 同步任务 > 微任务 > 宏任务