JS基础之事件循环机制探究

1,072 阅读2分钟

事件循环【Eventloop】

js是单线程非阻塞的脚本语言,单线程意味着在同一时间,只能做同一件事,所以js代码执行时只有一个主线程在执行。而非阻塞是指当代码需要进行一项异步任务(也就是不能及时获取结果,需要等待一定时间的任务)时,主线程会暂时挂起这个任务,然后在异步任务返回结果的时候根据返回的结果去执行相应的回调。

流程图

eventLoop.png

js 异步执行的运行机制

所有任务都在主线程上执行,形成一个执行栈。主线程之外,还存在一个任务队列(task queue)。只要异步任务有了运行结果,就在任务队列之中放置一个事件。

一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列"。那些对应的异步任务,结束等待状态,进入执行栈并开始执行。主线程将会不断重复上述步骤。

名词解释

执行栈

执行任务队列中的某个任务,这个被执行的任务就称为执行栈

主线程

主线程规定现在执行执行栈中的哪个事件。

当遇到一个异步事件后,并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不同的队列中,我们称之为任务队列。

当主线程将执行栈中所有的代码执行完之后,主线程将会去查看任务队列是否有任务。如果有,那么主线程会依次执行那些任务队列中的回调函数。

主线程循环:即主线程会不停的从执行栈中读取事件,会执行完所有栈中的同步代码。

异步任务

异步任务又分为宏任务微任务

微任务

一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前

常见的微任务有:

  • Promise.then
  • MutaionObserver
  • Object.observe(已废弃;Proxy 对象替代)
  • process.nextTick(Node.js)

宏任务

宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合

常见的宏任务有:

  • script (可以理解为外层同步代码)
  • setTimeout/setInterval
  • UI rendering/UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

node中的事件循环

笔者在一次面试中被问到了这个问题

在进程启动时,Node便会创建一个类似于while(true)的循环,每执行一次循环体的过程我们称为Tick。 每个Tick的过程就是查看是否有事件待处理,如果有,就取出事件及其相关的回调函数。 如果存在关联的回调函数,就执行它们。