-
Notifications
You must be signed in to change notification settings - Fork 11
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
node中的Event模块(上) #34
Comments
还有,你后面的打印结果是我上面的例子吗 |
嗯 懂了 这个结果是你上面的例子 |
因为 |
你好,我有两个疑问。
|
@toBeTheLight 正好watch这个blog,看到了你的问题,第二个问题我可以回答你: setTimeout(() => setTimeout(fn,0),0) 在运行event-loop的timers阶段的时候: |
setImmediate属于check观察者没错,但是并不是每次只执行链表中的一个回调函数,而是一次取出全部执行完:
nextTick是最后输出的。 |
js中的事件循环(Event Loop)
Event Loop
是指在js
执行环境中存在主执行线程和任务队列(Task Queue
),其中所有同步任务都在主执行线程中形成一个执行栈,所有异步任务都会放到任务队列中。Event Loop
会经历如下过程:参考资料:
macrotask
和microtask
上面说的异步任务中,分为
macrotask
(宏任务)和microtask
(微任务)两类,在挂起任务中,Js
引擎会按照类别将任务分别存放在这两种类型任务中。这两种任务执行的顺序如下:macrotask
任务队列中的第一个任务进行执行microtask
中的所有任务顺序执行macrotask
中的剩余任务执行这个步骤通过一个图来展示会比较直观:
图中
stack
表示主执行线程中的同步任务,而Background Threads
则是指macrotask
,在执行完主线程之后,会取出Macrotask Queue
(也叫Task Queue
)中的第一个任务setInterval
执行,执行完毕之后就会顺序执行下面的Microtask Queue
,直到所有Microtask Queue
中的任务都执行完毕了之后,才会执行下一个Macrotask
。其中
macrotask
类型包括:script
整体代码setTimeout
setInterval
setImmediate
I/O
UI rendering
microtask
类型包括:process.nextTick
Promise
(这里指浏览器实现的原生promise
)Object.observe
MutaionObserver
参考资料:
通过一段代码来验证一下上面的理论:
这段代码最后的输出结果如下:
大概讲解一下流程:
script
相当于一个Macrotask
,它是Macrotask Queue
中的第一个任务,先执行,所以打印出start
、end
Promise
相当于一个Microtask
,按照之前的理论,会先顺序执行完所有的Microtask
,所以此时会打印promise1
和promise2
。Microtask
之后,会将setTimeout1
和setInterval
推进Macrotask Queue
中,并且会执行此时Macrotask Queue
的第一个任务,也就是setTimeout1
,此时打印出setTimeout1
。Microtask
还是为空,所以会继续执行下一个Macrotask
,也就是setInterval
,此时打印出setInterval
setInterval
的task
时,会将下一个setTimeout
继续推进Macrotask Queue
,而且此时Microtask
仍然为空,继续执行下一个Macrotask
,所以打印出setTimeout2
setTimeout2
的时候,setTimeout2
里面的promise
已经推进Microtask Queue
中,所以此时会执行完Microtask Queue
中的任务,打印出promise3
Microtask Queue
的时候,一直执行的setInterval
后面的setTimeout3
会继续被推进Macrotask Queue
中,并且依次执行,直到setInterval
被取消。node中的
Event Loop
根据
node
官方文档的描述,node
中的Event Loop
主要有如下几个阶段:各个阶段执行的任务如下:
timers
阶段: 这个阶段执行setTimeout
和setInterval
预定的callback
;close
事件的callbacks
、被timers
设定的callbacks
、setImmediate()
设定的callbacks
这些之外的callbacks
;idle, prepare
阶段: 仅node
内部使用;poll
阶段: 获取新的I/O
事件, 适当的条件下node
将阻塞在这里;check
阶段: 执行setImmediate()
设定的callbacks
;close callbacks
阶段: 执行socket.on('close', ...)
这些callback
process.nextTick()
process.nextTick()
并没有在Event Loop
的执行阶段中,而是在Event Loop
两个阶段之间运行,根据上面说的,process.nextTick()
属于microtask
任务类型。根据
process.nextTick()
的运行性质,可以整理出下面的简图:也就是
process.nextTick()
有可能插入在Event Loop
各个阶段中setTimeout(fn,0)
VssetImmediate
Vsprocess.nextTick()
setTimeout(fn,0)
VssetImmediate
setTimeout(fn,0)
在timer
阶段执行,并且是在poll
阶段进行判断是否达到指定的time
时间才会执行setImmediate
在check
阶段才会执行两者的执行顺序要根据当前的执行环境才能确定,根据官方文档总结得出的结论是:
setImmediate
Vsprocess.nextTick()
setImmediate()
属于check
观察者,其设置的回调函数,会插入到下次事件循环的末尾,每次事件循环只执行链表中的一个回调函数。process.nextTick()
所设置的回调函数会存放到数组中,一次性执行所有回调函数。process.nextTick()
调用深度的限制,上限是1000,而setImmediate
没有;先来看一段代码:
在控制台中执行
node index.js
,得到的结果如下:分析如下:
node
中,nextTick
的优先级高于setTimeout
和setImmediate()
,所以会先执行nextTick
里面的信息打印。nextTick
,会慢于同步的nextTick
,所以nextTick4
会先于nextTick3
Event Loop
过程,首先执行timer
阶段,而此时setTimeout
所需要等待的时间是0,所以立即执行setTimeout2
和setTimeout3
里面的逻辑。而setTimeout1
由于设置了执行时间,不满足执行条件,被放到下一轮Event Loop
Event Loop
执行到check
阶段,于是打印出immediate1
、immediate2
Event Loop
,当setTimeout1
达到执行条件时执行参考资料:
-Node.js的event loop及timer/setImmediate/nextTick
-Node.js Event Loop 的理解 Timers,process.nextTick()
对
node
事件基础的一些总结,有不正确的地方还望指出,共同学习。The text was updated successfully, but these errors were encountered: