Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2021/02/05 - EventLoop的理解,浏览器环境和Node环境的区别 #48

Open
lxinr opened this issue Feb 5, 2021 · 0 comments
Open
Labels

Comments

@lxinr
Copy link
Owner

lxinr commented Feb 5, 2021

宏任务

V8引擎将宏任务安排成队列(先进先出)的形式执行,常见的宏任务有:

任务队列:

  • 渲染事件
  • 用户交互事件
  • js脚本执行
  • 网络请求、文件读写完成事件等等
  • ...
    延迟队列:
  • 定时器回调任务,如setTimeout\setInterval

微任务

对于每个宏任务而言,其内部都有一个微任务队列,引入微任务的初衷是为了解决异步回调的问题

V8引擎在每一个宏任务中定义一个微任务队列,当该宏任务执行完成,会检查其中的微任务队列,如果为空则直接执行下一个宏任务,如果不为空,则依次执行微任务,执行完成才去执行下一个宏任务

常见的微任务有:

  • MutationObserver
  • Promise.then/.reject/...
  • V8 的垃圾回收过程

浏览器端EventLoop的执行流程

  1. 整段js脚本作为第一个宏任务执行
  2. 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
  3. 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空
  4. 执行浏览器 UI 线程的渲染工作
  5. 检查是否有Web worker任务,有则执行
  6. 执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

Node端EventLoop的执行流程

三大关键阶段
  1. 执行定时器回调的阶段。检查定时器,如果到了时间,就执行回调。这些定时器就是setTimeoutsetInterval。这个阶段暂且叫它timer

  2. 轮询(英文叫poll)阶段。因为在node代码中难免会有异步操作,比如文件I/O,网络I/O等等,那么当这些异步操作做完了,就会来通知JS主线程,怎么通知呢?就是通过data

'connect'等事件使得事件循环到达poll阶段。到达了这个阶段后:
如果当前已经存在定时器,而且有定时器到时间了,拿出来执行,eventLoop 将回到timer阶段。
如果没有定时器, 会去看回调函数队列。

* 如果队列不为空,拿出队列中的方法依次执行
* 如果队列为空,检查是否有`setImmdiate`的回调
    * 有则前往`check`阶段(下面会说)
    * 没有则继续等待,相当于阻塞了一段时间(阻塞时间是有上限的), 等待`callback`函数加入队列,加入后会立刻执行。一段时间后自动进入`check`阶段。
  1. check阶段。这是一个比较简单的阶段,直接执行setImmdiate的回调

Nodejs和浏览器关于EventLoop的主要区别

两者最主要的区别在于浏览器中的微任务是在每个相应的宏任务中执行的,而nodejs中的微任务是在不同阶段之间执行的

@lxinr lxinr added the JS基础 label Feb 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant