阅读 103

JavaScript中的EventLoop(事件循环)机制

事件循环

  1. JavaScript是单线程,非阻塞的
  2. 浏览器的事件循环
  • 执行栈和事件队列
  • 宏任务和微任务
  1. node环境下的事件循环
  • 和浏览器环境有何不同
  • 事件循环模型
  • 宏任务和微任务

1.JavaScript是单线程,非阻塞的

  • 单线程:JavaScript主要用途是与用户交互,以及操作DOM。如果是多线程会有很多复杂的问题,例如两个线程同时操作DOM,一个删除当前DOM,一个操作当前DOM,所以为了避免这个问题,JS是单线程的。
  • 非阻塞:通过even loop实现

2.浏览器的事件循环

1.执行栈和事件队列
  • 执行栈:(主线程)同步代码的执行,按顺序添加到执行栈中

  • 事件队列:(任务队列)异步代码的执行,遇到异步事件不会等待它返回结果,而是将这个事件挂起,继续执行执行栈(主线程)中的其他任务。当异步事件返回结果,将它放到事件队列中,被放入事件队列不会立刻执行回调,而是等待当前执行栈(主线程)中所有任务执行完毕,主线程空闲状态,主线程会去查找事件队列中是否有任务,如果有,则取出排在第一的事件,并把这个事件对应的回调放到执行栈中,然后执行其中的同步代码。

  • 事件循环:代码执时分为同步任务和异步任务,同步任务直接进入主线程,异步任务进入任务队列。主线程任务执行完毕,从任务队列读取任务推入到主线程,重复该过程直到任务执行完毕,重复的过程成为事件循环。

2.宏任务和微任务

不同的异步任务被分为:宏任务和微任务

  • 宏任务:script、setTimeout()、setInterval()、postMesssage、I/O、UI交互事件

  • 微任务:new Promise().then()

3.运行机制
  1. 异步任务的返回结果会被放到一个任务队列中,根据异步事件的类型,会被放到对应的宏任务和微任务中。

  2. 当前执行栈为空时,主线程会查看微任务队列是否有事件存在

  • 存在,依次执行队列中的事件对应的回调,直到微任务队列为空,然后去宏任务队列中取出最前面的事件,把当前的回调加到当前当前指向栈。
  • 不存在,去宏任务队列中取出一个事件并把对应的回调加入当前执行栈
  1. 当前执行栈执行完毕后会立刻处理所有微任务队列中的事件,然后再去宏任务中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
总结:

在事件循环中,每进行一次循环操作成为tick,每一次tick的任务步骤如下:

  • 执行一个宏任务(栈中没有就中事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到为任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染
  • 渲染完毕之后,开始下一个宏任务

执行顺序:

  • 执行宏任务,然后执行宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
文章分类
前端
文章标签