事件循环是JavaScript的基本概念。面试必须问。我经常谈论它,但是您是否曾经想过为什么有事件循环?为什么会这样设计?
今天,我们将探索原因。
JavaScript用于实现涉及DOM操作的Web交互式逻辑。如果多个线程同时运行,则需要同时处理。为了简化它,它被设计为单个线程。该请求将再次阻止。如何做?
您可以将JS代码添加到任务中,然后将其放入任务队列中,并且主线程不断执行任务。
每次执行任务时,都会创建一个新的调用堆栈。
其中,计时器和网络请求实际上在其他线程中执行。执行完成后,将任务放在任务队列中,告诉主线程继续执行。
由于这些异步任务是在其他线程中执行的,然后由任务队列通知主线程,因此是事件机制,因此此周期称为事件循环。
在其他线程中执行的这些异步任务包括计时器(SetTimeout,setInterval),UI渲染,网络请求(XHR或FETCH)。
但是,事件循环存在一个严重的问题,没有优先级的概念,但仅按顺序进行实施。如果有很高的优先任务,则不会及时实施。因此,您必须设计一组切割机制。
然后只做一个高优先级任务队列。每次执行正常任务时,都会执行所有高优先级任务,然后执行一般任务。
通过结束机制,您的任务可以及时实现。
这是浏览器的事件循环。
普通的任务称为宏观掩饰(宏任务),高 - 外观任务称为Microtask。
宏任务包括:settimeout,setInterval,requestAnimationframe,ajax,fetch,脚本标签。
微任务包括:Promise。
如何了解宏任务的部门?
在其他线程运行之后,将计时器和网络请求通知主线程的一般异步逻辑,因此它们是宏任务。
这三种高质量任务也被充分理解。突变操作器和object.Observe都在监视对象的更改。更改是一件非常即时的事情。该过程的过程也很高。
这是浏览器中事件循环的设计:设计循环机制和任务队列是为了支持异步,解决主线程逻辑执行的问题,以及设计微型任务队列的插入机制是解决问题。尽快完成高质量的任务。
但是后来,JS的执行环境不仅是浏览器,而且是node.js。它还必须解决这些问题,但是它设计的事件循环更详细。
Node.js是一个新的JS运行环境。它还需要支持异步逻辑,包括计时器,IO,网络请求,这很明显,您也可以使用事件循环集运行。
但是,浏览器的循环集是为浏览器设计的。对于高性能服务器,设计仍然有些粗糙。
在哪里粗糙?
浏览器的事件循环分为两层优先级,一层是宏任务,第一层是micro -task。但是,宏任务之间没有优先级,并且微型任务之间没有优先级。。
Node.js任务宏任务也有优先级。例如,计时器计时器的逻辑比IO的逻辑高,因为它涉及时间,关闭资源的处理逻辑越准确是优先的。影响很小。
因此,宏任务队列被拆除为五个优先级:计时器,待处理,民意调查,检查,关闭。
解释这五个宏任务:
计时器回调:当涉及到时间时,执行越早,越准确,因此最高优先级易于理解。
待定回调:治疗异常的恢复,例如网络,IO和一些 *NIUX系统,将等待错误报告,因此必须处理它。
投票回调:处理IO数据,网络连接以及服务器的主要处理。
检查回调:执行SetImMediate的回调,其特征是IO之后的恢复。
关闭回调:关闭资源的回调,晚期执行没有影响,优先级是最低的。
因此,Node.js的事件循环像这样运行:
还有另一个要特别注意的区别:
Node.js的事件循环不是一次执行宏任务的浏览器,然后执行所有Micro -Task,而是执行一定数量的计时器宏任务,然后执行所有Micro -Tasks,然后执行一定数量的数量等待宏任务,然后执行所有微任务,剩余的民意调查,检查,关闭宏任务也是如此。-任务)
为什么是这样?
实际上,根据优先事项很容易理解:
假设浏览器中的宏任务为1,因此按顺序进行顺序执行,即宏任务,所有micro -tasks,另一个宏任务和所有micro -tasks。
Node.js的宏任务之间也有一个优先级,因此Node.js的事件循环每次都会运行所有当前的宏任务,然后运行Micro -Task,然后运行下一个优先级。
也就是说,一定数量的计时器宏任务,然后所有micro -task,一定数量的待定回调宏任务,然后是所有micro -tasks。
为什么是一个数字?
因为如果某个阶段的宏任务太多,则不会在下一阶段执行,因此限制有限,其余的下一个事件循环将继续执行。
除了宏任务的优先级外,微任务还将优先级划分。proces.nexttick有额外的先前优先级微任务,该任务在所有普通的微任务之前运行。
因此,node.js的事件循环的完整过程是:
与浏览器中的事件循环相比,它明显更为复杂,但是在我们先前的分析之后,我们也可以理解:
Node.js具有宏任务的优先级。从高到低的是计时器,待处理,民意调查,检查,关闭,它也将Micro -tasks划分,即NextTick的Micro -Tasks和其他微任务。执行过程是执行一定数量的宏任务(执行一定数量的宏任务(其余到当前优先级的下一个周期),然后执行proces..nexttick的微控制器,然后执行普通的微任务,然后执行下一个优先级。QuantityMacro task.quantity Macro task.essencethis持续循环。/准备阶段用于node.js内部逻辑,无需关注。
在浏览器事件循环中执行宏任务的方法的更改可以允许较早执行高优先级宏任务,但还设置了一个上限,以避免在下一阶段执行。
还需要注意的是民意调查阶段:如果执行到民意调查阶段,发现民意调查队列是空的,计时器队列或检查队列没有任务执行。这也是因为服务器主要是处理IO的,因此阻止此处可以更早响应。
完整的node.js的事件循环是这样的:
与浏览器的活动循环相比:
两个JS操作环境的事件循环的总体设计思想相似,但是Node.js的事件循环已经划分了宏任务和微任务,这很容易理解。毕竟,Node.js面对环境,环境,环境,环境,环境,环境,环境和环境以及浏览器以及浏览器不同,更重要的是,服务器对性能的要求将更高。
JavaScript首先用于编写Web交互式逻辑。为了避免多线程同时修改的同步问题,它被设计为单个线程。为了解决单线封锁的问题,它添加了一层调度逻辑,即循环循环和任务任务,将阻塞逻辑放在其他线程上,并支持异步。优先任务计划,引入了Micro -Task队列。这是浏览器的事件循环机理:执行每个宏任务,然后执行所有微任务。
Node.js也是JS运行环境。如果您想支持异步,也需要使用事件循环,但是服务器环境更复杂,性能要求更高。
Node.js中有5个宏任务,即计时器,待处理,轮询,检查,关闭。两个微型任务是分配的,即MicroController和其他Micro -Tasks process.nexttick。
Node.js的事件循环过程是当前阶段的一定数量的宏任务(剩余到下一个周期),然后执行所有微型任务。有6个计时器,待处理,空闲/准备,轮询,检查,关闭6阶段。
其中,闲置/准备阶段用于node.js内部,因此不在乎。
特别是,应该注意的是,如果您在此处执行,则民意调查队列为空,计时器和检查队列为空。它将始终在此处阻止IO,直到计时器和检查队列在继续循环之前进行调整。
事件循环是由JS设计的一组调度逻辑,用于支持异步和任务优先级。它针对浏览器,node.js(主要是任务优先级的粒度)等不同环境具有不同的设计。环境更加复杂,性能要求更高,因此事件循环设计更为复杂。