首先我们要知道js语言的特点,即js是单线程的解释性语言,也就是说同一时间只能做一件事。
事件循环
为了协调事件绑定、用户交互、js脚本、UI渲染、网络请求等行为,防止主线程的不阻塞,事件循环(Event Loop)的方案应运而生,即事件循环机制。
任务队列
事件循环是通过任务队列的机制来进行协调的,一个Event Loop可以有一个或多个任务队列。
Event Loop中每进行一次循环操作的任务处理的关键步骤如下:
- js分为同步任务和异步任务
- 同步任务都在主线程上执行,形成一个执行栈
- 主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就会在任务队列中放置一个事件
- 一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行
此步骤需要了解以下内容:
宏任务
- 可以理解为每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行的代码)
- 宏任务队列可以有多个
- 宏任务执行完成后要检查微任务队列,如果有微任务则优先执行所有微任务,执行完微任务以后再执行下一个宏任务,因此形成了事件循环机制
宏任务包括:
script(整体代码)
setTimeout
setInterval
ajax请求
DOM事件绑定(UI交互事件)
I/O
setImmediate(Node.js 环境)
微任务
- 可以理解为是在执行栈中当前任务执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前
- 微任务队列只有一个
- 微任务要先于setTimeout、setInterval、DOM事件绑定(UI交互事件)等的回调执行。只有微任务队列的所有微任务执行完之后才会执行宏任务的回调
微任务包括:
Promise.then()
Object.observe
process.nextTick (Node.js 环境)
运行机制
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,js线程继续接管,开始下一个宏任务(从事件队列中获取)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。