1. 概述
javaScript
是单线程的,意味着它一次只能执行一个任务。然而,许多操作,如网络请求、定时器等,都会导致延迟,如果程序在等待这些操作完成时,可能会操作一个阻塞的效果,影响用户体验。这个时候就需要事件循环 来进行一个调节:通过合理的安排任务的执行顺序,使得异步任务能够以非阻塞的方式运行。在搞清楚事件循环之前,需要明白javaScript
中的任务、任务队列等概念
2. javaScript中的任务
javaScript
程序里面的任务可以分为两类
- 同步任务 :没有被引擎挂起、在主线程上排队执行的任务。同步任务是按照代码的书写顺序依次执行的,只有前一个任务执行完毕,才能执行下一个任务,因此会阻塞 后续的任务执行。在事件循环中,同步任务的执行会一致持续,直到所有的同步任务执行完毕
- 异步任务 :被引擎挂起、放在一边,不进入主线程,而进入任务队列 的任务。异步任务是在将来的某个时间点执行的任务,不会阻塞后续任务的执行,异步任务通常会在一段时间后完成,并在完成时触发回调函数处理结果。 异步任务又可以分为两个子类,宏任务、微任务
- 宏任务 :代表一个独立的、完整的执行单元,在任务队列中排队等待执行。典型的宏任务包括,整体的
javaScript
代码、setTimeOut
、setTimeInterval
、Ajax
等 - 微任务 :微任务是一个更小的任务单位,它的执行优先级高于宏任务。当一个宏任务执行完毕后,在执行下一个宏任务之前,会立即处理微任务队列中的所有微任务。典型的微任务包括,
promise
、defineProperty
、Proxy
等
- 宏任务 :代表一个独立的、完整的执行单元,在任务队列中排队等待执行。典型的宏任务包括,整体的
3. 任务队列和事件循环
javaScript
运行时,除了一个正在运行的主线程,引擎还提供了一个任务队列(task queue),里面是各种需要当前程序处理的异步任务。实际上根据异步任务的类型,存在多个任务队列,如之前所说的,宏任务队列,微任务队列。
- 任务队列:是一种数据结构,用于存储不同类型的任务,如宏任务和微任务。任务会别添加到任务队列,等待事件循环将其取出并执行
- 宏任务队列:存储宏任务,每次事件循环迭代中只执行一个宏任务
- 微任务队列:存储微任务,这些微任务在宏任务执行完毕之后立即执行
引擎在执行所编写的代码顺序是:
- 主线程会去执行所有的同步任务。等到同步任务执行完毕之后,就会检查任务队列里面的异步任务
- 这里首先会从宏任务队列里面选择一个宏任务执行,执行完毕之后,则检查微任务队列并以此执行里面所有的微任务
- 当微任务队列中的任务执行完毕之后,重复步骤2,直到宏任务队列为空
在每次事件循环迭代中,同步任务的执行都是第一步,只有当所有 的同步任务执行完毕之后,事件循环机制才会去检查任务队列 ,并从宏任务队列 中选择一个宏任务执行,在执行宏任务的过程中如果产生了微任务,会将这些微任务添加到微任务队列,并等当前的宏任务执行完毕之后立即执行微任务队列里面的微任务。等微任务队列中的微任务执行完毕之后,则会选着宏任务队列中的下一个宏任务执行,依次循环
事件循环 :上诉执行顺序中的2->3->2->3...
就可以称为事件循环(Event Loop), 事件循环是 JavaScript 异步编程的基础机制,通过合理地管理任务队列、宏任务和微任务,使得异步操作能够在单线程环境中得到有效的协调和执行,从而提高了程序的响应性和用户体验。