关于Event loop的问题

Event loop即事件循环,就是指浏览器或者Node(JS运行的环境)用来解决JS单线程运行阻塞的问题的一种机制。 关于Event loop,它分为MacroTask(宏任务)和MicroTask(微任务)。

首先,我们来谈一下JS的单线程运行。

何为单线程?

当一个程序运行时,就可以视为一个进程。运行中的程序和程序所需要的资源都是进程,而一个进程一般是由多个线程组成的。
多个线程意味着有多个不同的执行流执行不同的任务。多线程运行时,不是其他线程等待一个执行完,而是各自运行。但是,同时多线程运行时占用的内存偏多,且会出现共享资源争夺的情况,容易造成很多麻烦的Bug。
而单线程是按顺序执行,不需要占用过多的内存资源。

那么为何JS会是单线程呢?

JS从诞生之初就是单线程。阮一峰老师在他的博客中提到:大概是因为不想让浏览器变得像多线程那样复杂,因为多线程需要共享资源、且有可能修改彼此的运行结果,对于一个网络脚本语言来说,太过于复杂了,还是单线程比较适合JS。而Event loop就是用来解决JS单线程运行阻塞、等待时间过长的一种机制。

宏任务(Macro Task)

宏任务是由宿主,也就是JS运行的环境(浏览器和Node),发起的。
script代码、setTimeout、setInterval、setImmediate、I/O(Node.js)、UI rending/UI事件都是宏任务的具体事件
在代码中,一般后运行,并会触发新一轮的Tick。

微任务(Micro Task)

微任务是由JS引擎发起的。
Promise、MutationObserve、Object.observe(已废弃;Proxy对象替代)、Process.nextTick(Node.js独有)
在代码中,一般会先行运行,并不会触发新一轮的Tick。

浏览器与Event loop

程序中,会设置两个线程,一个是负责程序本身的运行,为“主线程”(main thread);另一个则负责主线程与I/O操作之间的通信,即调用栈(执行栈)call-stack,所有的任务都会放在栈中等待被主线程执行。

在主线程中,最先执行的任务会存储在任务队列中放入执行栈中执行,当任务队列为空时,则会从微任务队列中选择任务放入到任务队列中,直至任务都被完成。执行进入Micro的检查点时,会先设置Micro的检查点为true,当Micro不为空时,选择一个任务task进入队列中,并将其设置为已选择的microtask,运行microtask,将已经执行完的microtask设置为null,清理indexDB事务,重新设置Micro检查点为false,更新界面。

浏览器中Event loop会先检查执行栈,如果执行栈为空,则去执行宏任务,宏任务执行完成之后,会去检查微任务队列,如果不为空,则依次执行微任务,直至微任务执行完成之后再去执行宏任务。

Node.js与Event loop

Node中Event loop中的libuv实现的。

什么是libuv?

libuv是一个高性能、事件驱动的异步I/O库。libuv封装了不同平台底层对于**异步I/O模型**的实现。\
现阶段的Node提供libuv作为封装层,使Node具备了跨平台的能力。

Node的Event loop被分为6个阶段:

  •  timers:执行setTimeout和setInterval中时间到期满足(达到最快定时器的阈值 - 由于调度会产生一些延时)的callback。
  •  pending callback:某些系统操作的回调(例如:TCP错误类型)
  •  poll:

    1. 执行I/O回调
    2. 处理轮询队列中的事件
    如果poll队列不为空,则会循环遍历执行它们的callback队列;如果有setImmediate()需要回调执行,则停止poll阶段进入check阶段执行回调;如果没有setImmediate(),poll将callback放入队列中执行;如果poll为空,则会判断timer是否超时,如果有的话则回到timer。
    

  •  check:如果poll已完成或者闲置并且setImmediate()已排队,则立即执行check阶段。
  •  close callback:执行close事件中的callback。

setImmediate()与定时器

setImmediate()在poll阶段执行完成或者闲置之后立即执行,在check阶段\
定时器在timer阶段执行

Process.nectTick()

process.nextTick()从技术上讲,并不是事件循环的一部分。在每个阶段完成之后,如果存在nextTick就会清空队列中所有的callback立即执行nextTick。

浏览器的Event loop与Node中的loop的区别

Node端的事件循环,MicroTask在事件循环的各个阶段之间执行
浏览器中的时间循环,MicroTask在事件循环的MacroTask执行完之后再执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值