一、基本概念

Event Loop

Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。

任务队列(task queue)

task,就是任务的意思,我们这里理解为每一个语句就是一个任务

  1. console.log(1);
  2. console.log(2);

如上语句,其实就是就可以理解为两个 task
queue 呢,就是FIFOfirst in first out 先进先出)的队列!
所以 Task Queue 就是承载任务的队列。而 JavaScriptEvent Loop 就是会不断地过来找这个 queue,问有没有 task 可以运行运行。

同步任务(SyncTask)、异步任务(AsyncTask)

先同步任务 后异步任务

同步任务

  • 基本上所有非微任务宏任务的 script
  • Promise 构造函数是同步执行的

    异步任务

  • promise.then 中的函数是异步执行的。

  • 所有的宏任务(MacroTask)、微任务(MicroTask)

    例子

    ```javascript const promise = new Promise((resolve, reject) => { // Promise 构造函数内是同步 console.log(1) resolve() console.log(2) }) promise.then(() => { // promise.then 中的函数是异步 console.log(3) }) console.log(4)

// 1 2 4 3

  1. <a name="yM0XM"></a>
  2. ###
  3. <a name="6RX3N"></a>
  4. ## 宏任务(MacroTask)、微任务(MicroTask)
  5. > 先微任务 后宏任务
  6. <a name="E3IIS"></a>
  7. ### MacroTask(宏任务)
  8. - `script` 全部代码、面试题中常见 console.log
  9. - `setTimeout`
  10. - `setInterval`
  11. - `setImmediate`(浏览器暂时不支持,只有IE10支持,具体可见`[MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setImmediate)`)
  12. - `I/O`、`UI Rendering`。
  13. <a name="zrE9Q"></a>
  14. ### MicroTask(微任务)
  15. - `Process.nextTick(Node独有) `
  16. - `Promise.then catch finally` (注意不是 Promise)
  17. - `Object.observe(废弃)`
  18. - `MutationObserver`
  19. <a name="Diyjn"></a>
  20. # 二、浏览器环境下的 Event Loop
  21. <a name="4XFcC"></a>
  22. ## 1.
  23. <a name="Fas5h"></a>
  24. # 三、Node 环境下的 Event Loop
  25. `Node`中的`Event Loop`是基于`libuv`实现的,而`libuv`是 `Node` 的新跨平台抽象层,libuv使用异步,事件驱动的编程方式,核心是提供`i/o`的事件循环和异步回调。libuv的`API`包含有时间,非阻塞的网络,异步文件操作,子进程等等。`Event Loop`就是在`libuv`中实现的。

┌───────────────────────────┐ ┌─>│ timers │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ pending callbacks │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ idle, prepare │ │ └─────────────┬─────────────┘ ┌───────────────┐ │ ┌─────────────┴─────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └─────────────┬─────────────┘ │ data, etc. │ │ ┌─────────────┴─────────────┐ └───────────────┘ │ │ check │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ └──┤ close callbacks │ └───────────────────────────┘ ```

从上图中,大致看出node中的事件循环的顺序:
外部输入数据—>轮询阶段(poll)—>检查阶段(check)—>关闭事件回调阶段(close callback)—>定时器检测阶段(timer)—>I/O事件回调阶段(pending callbacks)—>闲置阶段(idle, prepare)—>轮询阶段(按照该顺序反复运行)…

  • timers 阶段:这个阶段执行timer(setTimeout、setInterval)的回调
  • pending callbacks 阶段:处理一些上一轮循环中的少数未执行的 I/O 回调
  • idle, prepare 阶段:仅node内部使用
  • poll 阶段:获取新的I/O事件, 适当的条件下node将阻塞在这里
  • check 阶段:执行 setImmediate() 的回调
  • close callbacks 阶段:执行 socket 的 close 事件回调

1. timers 阶段

2. pending callbacks 阶段

3. poll 阶段

4. check 阶段

5. close callbacks 阶段

6. setImmediate() 的setTimeout()的区别

7. Process.nextTick()

参考链接