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. 微任务队列

在宏任务的执行过程中,往往会遇到遇到许多异步子任务,即微任务,它们属于父任务中的一部分,应该在父任务执行完后立即执行。因此,在宏任务执行过程中,如果遇到微任务,不应该立即执行,而是应该放入微任务队列中,然后向下继续执行宏任务,待宏任务执行完成后,立即依次执行微任务队列中的所有微任务。

四、事件循环机制

  • 读取任务队列,取出一个宏任务
  • 执行宏任务
  • 如果在执行过程中遇到微任务,将其添加到微任务队列中
  • 宏任务执行完毕后,立即依次执行微任务队列中的所有微任务
  • 开启下一轮循环

参考