EventLoop

Event Loop(事件循环)

1.javascript是单线程的,非阻塞的

为什么js是单线程的?

JS的主要作用是与用户进行交互,以及操作dom。假如js为多线程的,现在有两个线程需要同时操作dom,一个线程把节点删除了,另一个线程要去操作这个dom,这个时候该以哪个线程为准呢?
所以JS是单线程的,以避免这种事情的发生。
但是JS也可以开启子线程的 web worker, 但是有很多限制,子线程受主线程的控制的。
所有的新线程都完全受主线程控制,无法单独执行。
也就是新的线程只是主线程的子线程
这些新的线程是没有执行I/O的操作权限的,只能为主线称分担一些计算任务,所以这些线程没有完整的功能不能算是真正的新线程。

非阻塞
通过eventLoop来实现js的非阻塞

2.浏览器的事件循环

JS在异步代码的执行过程中,不会一直等待异步事件的返回结果,而是将异步事件进行挂起,继续执行栈中的其他任务。
当异步事件返回结果时,将它放到事件队列中,
被放入事件队列的后并不会立即执行,而是等待当前执行栈中所有的任务执行完成后,主线程处于空闲状态的时候,去查找事件队列中是否有任务,如果有,会取出排在第一位的事件,
并把这个事件对应的回调放到执行栈中,然后执行同步代码。

3.宏任务和微任务

为什么要有微任务?

页面渲染事件,IO的完成事件等等 都会随时加入到任务队列中,队列的规则是先进先出,不能准确的控制这些事件添加到队列的位置。
如果突然有高优先级的任务需要执行,只有一种任务类型就不满足了,所以有了微任务队列

node环境下的事件循环
node 环境中时间循环依赖libuv引擎
node10版本之前,微任务会在事件循环的各个阶段之间执行,一个阶段执行完毕后才会去执行微任务队列
node10版本之后,变得和浏览器一致,在执行一个宏任务之后就会立即执行所有的微任务

┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<──connections─── │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘

Node时间循环的各个阶段

1.定时器检测阶段(timers): 这个阶段执行定时器队列中的回调如 setTimeout() 和 setInterval()。
2.I/O事件回调阶段(I/O callbacks): 这个阶段执行几乎所有的回调。但是不包括close事件,定时器和setImmediate()的回调。
3.闲置阶段(idle, prepare): 这个阶段仅在内部使用,可以不必理会
4.轮询阶段(poll): 等待新的I/O事件,node在一些特殊情况下会阻塞在这里。
5.检查阶段(check): setImmediate()的回调会在这个阶段执行。
6.关闭事件回调阶段(close callbacks): 例如socket.on(‘close’, …)这种close事件的回调

宏任务:
setImmediate
setTimeout
setInterval
script(整体代码)
I/O 操作等。

微任务:
process.nextTick
new Promise().then(回调)

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2019-2021 伯温

请我喝杯咖啡吧~