今天去看eventloop工作循环的时候,看了许多文章,越看越含糊,整得很乱,放了许多图,哈哈,对不起亲们,我的确看的云里雾里,不如自己凭着这些文章的大致思路,来梳理一下自己能够了解的过程
js
在说这个流程之前,咱们先来说一下,几个概念,同步代码,宏使命,微使命,栈,堆,同步使命,异步使命,单线程
咱们都知道,js 是单线程,node 也是单线程,所谓的单线程便是一起只能做一件工作,其他的工作在后面排,像招商银行的客服一样,one by one and next 主线程便是 那个 单线程 可是要搞清楚,js是单线程,宿主环境或许不是单线程,浏览器能够是多线程,node环境是单线程
概念
同步代码 和 同步使命其实是一个概念,是履行器从上至下能立刻完结的工作,不会被引擎挂起、不需要过多损耗,发费过长的工作去完结的工作,同步使命的使命行列就放在栈里边,栈区存放的都是一些简略的工作,
异步使命,是浏览器在将来某个时刻 或者说 今后满意某一条件等才会去履行的一个使命,它被放在了一个使命行列里边,当主线程处理完结后,会去处理使命行列的异步使命。
那么 不同的异步使命依据性质不一样,分为两类,便是 宏使命 和 微使命,所以,同步使命是包含两种使命,一种是宏使命,一种是微使命
宏使命 和 微使命 是怎样区别来着,为什么这个便是宏使命,这个便是微使命呢,这儿说不得,太长了, 那就不管上面的概念,我记住哪一个是宏 和 微 就OK了,
这儿写了一个表格,在node环境和js环境 不同的工作区别的使命种类还有些不一样
使命工作 | node环境 | 浏览器环境 |
---|---|---|
IO | 宏使命 | 宏使命 |
setTimeOut,setInterVal | ||
setImmediate | ❎ | |
requestAnimationFrame | ❎ | 宏使命 |
process.nextTick | ❎ | 微使命 |
MutationObserver | 微使命 | ❎ |
Promise.then catch finally | 微使命 | 微使命 |
async/await函数中的后续操作 | 微使命 | 微使命 |
堆和栈: js代码履行的时候会将不同的变量存于内存中的不同方位便是仓库的方位, 堆(heap)和栈(stack)
其间,堆里存放着一些目标。而栈中则存放着一些根底类型变量以及目标的指针。
怎样记忆他们呢,
堆,一堆,许多,存放的东西许多,便是一堆,便是堆, 引证数据类型,目标,存许多东西,放在这儿,
其他的便是栈,栈中存放着一些根底类型变量以及目标的指针。相对比较简略一些的东西
可是履行栈 和 栈 是两个概念, 履行栈能够简略了解履行上下文的环境
ok, 概念简略说完了,说说全体的eventLoop
主线程会把同步使命(同步代码)顺次履行,在履行同步代码的一起,或许会产生异步使命,或许是宏使命,也或许是微使命,把这些使命顺次放进一个行列里边,在同步使命履行完结后,会去履行异步使命, 这儿不说什么 monitoring process,Event table, Event queue , 简略点
好,同步代码履行完结,在此期间 ,会产生宏使命, 或许会有微使命, 假如有微使命,那么肯定是要先去履行微使命,再去履行宏使命
可是许多文章都是说,宏使命履行期间,假如有微使命进入,在当时的宏使命履行结束后,优先履行剩余的微使命,微使命是紧急刺进工作,需要优先履行,便是下面这张图
最初在哪里,异步使命应该有一个最初,假如最初有微使命,和宏使命呢,为啥不直接说呢
看的我心慌 ,究竟是不是先履行微使命,在履行宏使命,
定论
那,定论就出来了: 主线程会把同步使命(同步代码)顺次履行,在履行同步代码的一起,或许会产生异步使命,或许是宏使命,也或许是微使命,把这些使命顺次放进一个行列里边,在同步使命履行完结后,会去履行异步使命,异步使命中,假如存在微使命,先履行微使命,在履行宏使命,假如在宏使命履行中产生了微使命,那么在本次宏使命履行结束后,履行剩余的微使命,微使命中假如还存在微使命,接着履行,直到履行结束,在去履行下一个宏使命。
额定的
说一些额定的:
-
异步使命不在主线程里边履行,在宿主环境履行,履行完的使命有回调函数,会放在行列里,按顺序顺次等候主线程来履行(想想平常恳求的接口)
-
宏使命和微使命放的不是一个行列,是两个行列,先履行的永远是微使命的行列
node
Node.js 是一个新的 JS 运转环境,它相同要支持异步逻辑,包含定时器、IO、网络恳求,很明显,也能够用 Event Loop 那一套来跑。
可是呢,浏览器那套 Event Loop 便是为浏览器规划的,对于做高性能服务器来说,那种规划还是有点粗糙了。
哪里粗糙呢?
浏览器的 Event Loop 只分了两层优先级,一层是宏使命,一层是微使命。可是宏使命之间没有再区分优先级,微使命之间也没有再区分优先级。
而 Node.js 的宏使命之间也是有优先级的,比方定时器 Timer 的逻辑就比 IO 的逻辑优先级高,由于涉及到时刻,越早越精确;而 close 资源的处理逻辑优先级就很低,由于不 close 最多多占点内存等资源,影响不大。
于是就把宏使命行列拆成了五个优先级:Timers、Pending、Poll、Check、Close。
解释一下这五种宏使命:
Timers Callback:涉及到时刻,肯定越早履行越精确,所以这个优先级最高很容易了解。
Pending Callback:处理网络、IO 等反常时的回调,有的 *niux 体系会等候产生过错的上报,所以得处理下。
Poll Callback:处理 IO 的 data,网络的 connection,服务器首要处理的便是这个。
Check Callback:履行 setImmediate 的回调,特点是刚履行完 IO 之后就能回调这个。
Close Callback:关闭资源的回调,晚点履行影响也不到,优先级最低。
所以呢,Node.js 的 Event Loop 便是这样跑的了:
还有一点不同要特别注意:
Node.js 的 Event Loop 并不是浏览器那种一次履行一个宏使命,然后履行一切的微使命,而是履行完必定数量的 Timers 宏使命,再去履行一切微使命,然后再履行必定数量的 Pending 的宏使命,然后再去履行一切微使命,剩余的 Poll、Check、Close 的宏使命也是这样。
为什么这样呢?
其实依照优先级来看很容易了解:
假定浏览器里边的宏使命优先级是 1,所以是依照先后顺序顺次履行,也便是一个宏使命,一切的微使命,再一个宏使命,再一切的微使命。
而 Node.js 的 宏使命之间也是有优先级的,所以 Node.js 的 Event Loop 每次都是把当时优先级的一切宏使命跑完再去跑微使命,然后再跑下一个优先级的宏使命。
也便是必定数量的 Timers 宏使命,再一切微使命,再必定数量的 Pending Callback 宏使命,再一切微使命这样。
为什么说是必定数量呢?
由于假如某个阶段宏使命太多,下个阶段就一向履行不到了,所以有个上限的限制,剩余的下个 Event Loop 再持续履行。
除了宏使命有优先级,微使命也区分了优先级,多了一个 process.nextTick 的高优先级微使命,在一切的一般微使命之前来跑。
所以,Node.js 的 Event Loop 的完好流程便是这样的:
- Timers 阶段:履行必定数量的定时器,也便是 setTimeout、setInterval 的 callback,太多的话留到下次履行
- 微使命:履行一切 nextTick 的微使命,再履行其他的一般微使命
- Pending 阶段:履行必定数量的 IO 和网络的反常回调,太多的话留到下次履行
- 微使命:履行一切 nextTick 的微使命,再履行其他的一般微使命
- Idle/Prepare 阶段:内部用的一个阶段
- 微使命:履行一切 nextTick 的微使命,再履行其他的一般微使命
- Poll 阶段:履行必定数量的文件的 data 回调、网络的 connection 回调,太多的话留到下次履行。假如没有 IO 回调而且也没有 timers、check 阶段的回调要处理,就堵塞在这儿等候 IO 工作
- 微使命:履行一切 nextTick 的微使命,再履行其他的一般微使命
- Check 阶段:履行必定数量的 setImmediate 的 callback,太多的话留到下次履行。
- 微使命:履行一切 nextTick 的微使命,再履行其他的一般微使命
- Close 阶段:履行必定数量的 close 工作的 callback,太多的话留到下次履行。
- 微使命:履行一切 nextTick 的微使命,再履行其他的一般微使命
比起浏览器里的 Event Loop,明显复杂了许多,可是经过咱们之前的分析,也能够了解:
定论
Node.js 对宏使命做了优先级区分,从高到低分别是 Timers、Pending、Poll、Check、Close 这 5 种,也对微使命做了区分,也便是 nextTick 的微使命和其他微使命。履行流程是先履行完当时优先级的必定数量的宏使命(剩余的留到下次循环),然后履行 process.nextTick 的微使命,再履行一般微使命,之后再履行下个优先级的必定数量的宏使命。。这样不断循环。其间还有一个 Idle/Prepare 阶段是给 Node.js 内部逻辑用的,不需要关怀。
改变了浏览器 Event Loop 里那种一次履行一个宏使命的方法,能够让高优先级的宏使命更早的得到履行,可是也设置了个上限,防止下个阶段一向得不到履行。
不同点:
- 浏览器履行宏使命没有优先级,顺次履行,而且履行完结本次一切的宏使命,node宏使命有优先级,只能履行必定的宏使命,
- 浏览器履行微使命无优先级,顺次履行,node 有优先级,先履行 process.nextTick,在履行剩余的微使命。
如有过错,还请指出,加以改正,感谢。