JavaScript 事件循环
本文将介绍 JavaScript 的运行机制 - 事件循环。
一、单线程
为了避免复杂性,JavaScript 是单线程的。
二、任务的划分
1. 划分 - 同步与异步
部分任务执行耗时较长,如果由 JavaScript 的单线程顺序执行,可能导致页面长时间无响应,影响用户体验。
例如:发起网络请求,setTimeOut、等待按钮点击事件触发
因此,JavaScript 将它们划分为异步任务,以异步的方式执行,避免堵塞式等待。
2. 划分 - 宏任务与微任务
考虑到异步任务的不同特点,异步任务又被划分为宏任务和微任务,如下:
宏任务:
称为 Task
每个宏任务都是独立的任务
宏任务由环境发起
浏览器执行了网络请求后,发起了一个回调宏任务
包括 script 脚本的执行、setTimeout、setInterval、IO 等
微任务:
- 称为 Jobs
- 属于父任务中的一部分,应该在父任务执行完后立即执行
- 微任务由 JavaScript 自身发起
- 包括
.then/catch/finally
、MutationObserver、process.nextTick
等
三、任务队列与微任务队列
1. 任务队列
为了 实现异步执行 ,异步任务将会交由 “定时触发器线程”、”异步 http 请求线程” 等执行。为了能够 获取异步任务的执行结果 ,异步任务执行结束后 “事件触发线程” 会将回调事件放入任务队列中,从而 JavaScript 线程可以读取并执行,这个回调事件便是宏任务。
2. 微任务队列
在宏任务的执行过程中,往往会遇到遇到许多异步子任务,即微任务,它们属于父任务中的一部分,应该在父任务执行完后立即执行。因此,在宏任务执行过程中,如果遇到微任务,不应该立即执行,而是应该放入微任务队列中,然后向下继续执行宏任务,待宏任务执行完成后,立即依次执行微任务队列中的所有微任务。
四、事件循环机制
- 读取任务队列,取出一个宏任务
- 执行宏任务
- 如果在执行过程中遇到微任务,将其添加到微任务队列中
- 宏任务执行完毕后,立即依次执行微任务队列中的所有微任务
- 开启下一轮循环