js的事件循环机制

1.概述

首先我们需要知道,js是单线程的,每次只能执行一个任务,并且按照顺序执行。当运行到需要等待的异步任务时,异步任务的执行会被挂起等待,同步任务继续按顺序执行,等到同步任务执行完毕,再继续执行异步任务。也就是说js的执行是是非阻塞的,异步的。

下面是一个简单的例子

const main = () => {
    const fun1 = () => console.log(1)
    const fun2 = () => console.log(3)
    const fun3 = () => setTimeout(() => console.log(4), 0);
    const fun4 = () => setTimeout(() => console.log(6), 0);

    fun1()
    console.log(2)
    fun2()
    fun3()
    setTimeout(() => console.log(5), 0);
    fun4()
    console.log(7)
    setTimeout(() => console.log(8), 0);
}
main()
js的事件循环机制插图
执行结果

2.事件循环的具体的执行顺序

先同步,再异步
同步任务在主线程被按顺序压入栈(Stack)中执行,异步任务会被按顺序注册回调函数推入队列(Queue)等待栈中所有任务执行完毕之后由内部机制将队列中的第一个回调函数压入栈中执行,在执行完这个队列中的任务之后,会检测栈中是否还有其他同步任务,也就是说会回到刚开始的地方,如此往复实现循环,这就是Event Loop 事件循环机制。
异步任务主要由宏任务(MacroTask/Tasks)和微任务(MicroTask/Jobs)组成,在栈中的同步任务执行完毕之后,检测是否有微任务,如果有则按顺序执行所有微任务,否则会检测是否有宏任务,如果有则将宏任务推入栈中执行,执行一个宏任务完毕之后会继续检测是否还有微任务,直至所有任务完成,js执行完毕。

3.常见的宏任务与微任务

macro-task(宏任务):

  • script(整体代码)
  • setTimeout
  • setInterval
  • setImmediate
  • I/O (比如Ajax操作从网络读取数据)
  • UI render

micro-task(微任务):

  • process.nextTick
  • Promise
  • Async/Await(实际就是promise)
  • MutationObserver(html5新特性)