We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
javascript 从诞生之日起就是一门单线程的非阻塞的脚本语言。
JavaScript
Javascript
Ajax
也正是javascript的这两个特点,需要一种执行同步任务、且在异步任务及时按需执行的机制,这就是事件循环。
事件循环是用来协调事件、用户交互、脚本、渲染、网络的一种浏览器内部机制。一般我们所指的事件循环是指渲染过程中的脚本执行的机制,也就是浏览器一个渲染进程内主线程所控制的循环。
一个Event loop有一个或多个task quenes。task quenes是一组tasks的集合。
Event loop
task quenes
tasks
任务队列是集合,而不是队列,因为事件循环处理模型的第一步是从所选队列中获取第一个可运行的任务,而不是将第一个任务出队。
任务队列里的任务也分为不同的类型,常见的有宏任务和微任务 ,与宏任务取第一个可运行的任务不同,微任务所处的是一个先进先出的队列。 (为什么要区分宏任务和微任务:在下一次 Event loop 之前进行插队)
宏任务
微任务
一个Event Loop,Microtask 是在 Macrotask 之后调用,Microtask 会在下一个Event Loop 之前执行调用完,并且其中会将 Microtask 执行当中新注册的 Microtask 一并调用执行完,然后才开始下一次 Event loop,所以如果有新的 Macrotask 就需要一直等待,等到上一个 Event loop 当中 Microtask 被清空为止。由此可见, 我们可以在下一次 Event loop 之前进行插队。
作者:evan
链接:https://www.zhihu.com/question/316514618/answer/1311354630
常见的 :setTimeout、setInterval、setImmediate 、 script(整体代码)、 I/O 操作、UI 交互事件、postMessage 、requestAnimationFrame等。
setTimeout
setInterval
setImmediate
script
I/O
postMessage
requestAnimationFrame
没有明确指定,但是通常认为 : new Promise().then(callback)、MutationObserve 、await 和 process.nextTick(NodeJS 等。
new Promise().then(callback)
MutationObserve
await
process.nextTick(NodeJS
执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
Event Loop 的循环过程简略版如下:
Event Loop
task quene
hasARenderingOpportunity
resize
scroll
matchMedia
IntersectionObserver
task queues
task
microtask queue
requestIdleCallback
下图(源)是chrome对于事件循环处理的完整逻辑:
从规范中可以注意到,有两个函数比较特殊:一个是算作宏任务的requestAnimationFrame(rAF),另外一个是requestIdleCallback(rIC)。
requestAnimationFrame(rAF)
requestIdleCallback(rIC)
rAF 是官方推荐的用来做一些流畅动画所应该使用的 API,其特点为:
rAF
比如一般显示器刷新率为60HZ,则每秒最多绘制60此,也就是1000ms / 60 ≈ 16.7ms执行一次
1000ms / 60 ≈ 16.7ms
在闲时进行事件的处理,可以用来处理一些优先级低但是耗性能的任务。其特点为:
timeout
50ms
//可在稳定的浏览器界面不断输入该代码查看间隔 requestIdleCallback((deadline)=>{ console.log(deadline.timeRemaining()) })
Node11 之后一些特性已经向浏览器看齐了,两者最主要的区别是:
IO的延迟回调
process.nextTick
timers
pending callbacks
idle, prepare
poll
check
close callbacks
事件循环如下图(源):
Node11及之后会在宏任务执行完毕后会直接执行微任务;而Node11之前的可能出现例外,比如timer阶段第一个定时器执行完毕了,第二个定时器也恰好到时间,这时候会优先执行定时器,check阶段有多个setImmediate也是如此,也就是说Node11之前,在某个阶段存在的可执行事件都会优先执行,而后才执行微任务。
timer
HTML规范:event-loop requestAnimationFrame 执行机制探索
The text was updated successfully, but these errors were encountered:
对于 #24 的提问,在不需要渲染的情况下,是后面渲染相关的步骤不会执行,不是后面所有的步骤;不需要渲染,则hasARenderingOpportunity就是为false ,所以 requestIdleCallback是会执行的。
Sorry, something went wrong.
No branches or pull requests
浏览器为什么有事件循环
javascript 从诞生之日起就是一门单线程的非阻塞的脚本语言。
JavaScript
代码的线程只有一个主线程Javascript
代码运行一个异步任务的时候(像Ajax
从网络读取数据等),主线程会挂起这个任务,然后异步任务返回结果的时候再根据特定的结果去执行相应的回调函数。也正是javascript的这两个特点,需要一种执行同步任务、且在异步任务及时按需执行的机制,这就是事件循环。
Event Loop(事件循环)
事件循环是用来协调事件、用户交互、脚本、渲染、网络的一种浏览器内部机制。一般我们所指的事件循环是指渲染过程中的脚本执行的机制,也就是浏览器一个渲染进程内主线程所控制的循环。
task quenes(任务队列)
一个
Event loop
有一个或多个task quenes
。task quenes
是一组tasks
的集合。task and microtask(宏任务和微任务)
任务队列里的任务也分为不同的类型,常见的有
宏任务
和微任务
,与宏任务取第一个可运行的任务不同,微任务所处的是一个先进先出的队列。(为什么要区分宏任务和微任务:在下一次 Event loop 之前进行插队)
宏任务(macro-task)
常见的 :
setTimeout
、setInterval
、setImmediate
、script
(整体代码)、I/O
操作、UI 交互事件、postMessage
、requestAnimationFrame
等。微任务(micro-task)
没有明确指定,但是通常认为 :
new Promise().then(callback)
、MutationObserve
、await
和process.nextTick(NodeJS
等。Event Loop 处理过程
执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
Event Loop
的循环过程简略版如下:task quene
取出一个可执行的宏任务,放入到执行栈中去执行,如果没有可选的宏任务,则直接跳到微任务处理步骤hasARenderingOpportunity
为 false,该参数主要是判断当前界面是否有渲染机会,浏览器会根据硬件(如刷新率)和其他因素(页面性能和页面不可见等)。hasARenderingOpportunity
为 true,浏览器会在合适的时机去重新渲染。(如果无需渲染,则后续的渲染相关步骤都不会触发。)resize
事件scroll
事件matchMedia
requestAnimationFrame
IntersectionObserver
回调task queues
里没有task
且microtask queue
是空的,同时渲染时机变量hasARenderingOpportunity
为 false ,去执行 idle period(requestIdleCallback
)下图(源)是chrome对于事件循环处理的完整逻辑:

从规范中可以注意到,有两个函数比较特殊:一个是算作宏任务的
requestAnimationFrame(rAF)
,另外一个是requestIdleCallback(rIC)
。requestAnimationFrame
rAF
是官方推荐的用来做一些流畅动画所应该使用的 API,其特点为:比如一般显示器刷新率为60HZ,则每秒最多绘制60此,也就是
1000ms / 60 ≈ 16.7ms
执行一次requestIdleCallback
在闲时进行事件的处理,可以用来处理一些优先级低但是耗性能的任务。其特点为:
timeout
,可以指定该任务在该时间后一定会执行,不会再等待空闲。50ms
NodeJS的事件循环顺序
Node11 之后一些特性已经向浏览器看齐了,两者最主要的区别是:
setImmediate
、IO的延迟回调
和process.nextTick
等),所以Node的事件循环是多阶段的,一旦一个阶段执行完毕就立刻执行对应的微任务队列。(如果我们只看Node宏任务与微任务,则与浏览器一致,执行完宏任务就执行微任务)Node的不同阶段及事件循环
timers
:此阶段执行由setTimeout
和setInterval
设置的回调。pending callbacks
:执行推迟到下一个循环迭代的 I/O 回调。idle, prepare
, :仅在内部使用。poll
:取出新完成的 I/O 事件;执行与 I/O 相关的回调(除了关闭回调,计时器调度的回调和setImmediate
之外,几乎所有这些回调)。适当时Node 将在此处阻塞。check
:在这里调用setImmediate
回调。close callbacks
:一些关闭回调,例如 socket.on('close', ...)。
事件循环如下图(源):

Node11前后差异
Node11及之后会在宏任务执行完毕后会直接执行微任务;而Node11之前的可能出现例外,比如
timer
阶段第一个定时器执行完毕了,第二个定时器也恰好到时间,这时候会优先执行定时器,check
阶段有多个setImmediate
也是如此,也就是说Node11之前,在某个阶段存在的可执行事件都会优先执行,而后才执行微任务。参考
HTML规范:event-loop
requestAnimationFrame 执行机制探索
The text was updated successfully, but these errors were encountered: