什么是Event Loop

首先Event Loop(事件循环)是指计算机系统的一种运行机制。

它是浏览器或者Node用来解决JavaScript单线程运行时不会阻塞的一种机制,我们经常都会使用异步,而这种机制就是异步的原理。

先来说一下浏览器的Event Loop

JavaScript代码的执行过程中,除了依靠函数调用栈来确定函数的执行顺序外,还会依靠task queue(任务队列)(先进先出)来让另外一些代码的执行

Javascript单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行(代码从上到下的执行),异步任务会在异步任务有了结果后,将对应的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

一个线程中,事件循环是唯一的,但是任务队列可以拥有多个。

任务队列又分为task(宏任务)与microtask(微任务)。

浏览器的异步实现:

1.宏观:浏览器多线程

2.微观:Event Loop

task(普通任务,宏任务):script(整体代码), setTimeout/ setInterval, setImmediate, I/O, UI rendering。

microtask(微任务):Promise, Object.observe(监听对象变化的方法), MutationObserver(监听Dom结构变化的API), postMessage(window对象之间进行通信的方法)

 事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始(全局任务也是宏任务)。之后全局进入函数调用栈。直到调用栈清空(宏任务执行完毕),然后执行所有的microtask(微任务)。当所有可执行的microtask(微任务)执行完后。循环再次从task(宏任务)开始,执行完毕宏任务之后,再执行所有的microtask(微任务),这样一直循环下去。 如下图

requestAnimationFrame处于渲染阶段,不属于任务队列

下面来一段代码示例来按上述事件循环顺序来走一下

console.log("start");
setTimeout(() => {
  console.log("setTimeout");
  new Promise(resolve => {
    console.log("promise inner1");
    resolve();
  }).then(() => {
    console.log("promise then1");
  });
}, 0);
new Promise(resolve => {
  console.log("promise inner2");
  resolve();
}).then(() => {
  console.log("promise then2");
});
// start->promise inner2->promise then2->setTimeout->promise inner1->promise then1

然后再来一个稍微复杂点的例子

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  return Promise.resolve().then(_ => {
    console.log("async2 promise");
  });
}
console.log("start");
setTimeout(function() {
  console.log("setTimeout");
}, 0);
async1();
new Promise(function(resolve) {
  console.log("promise1");
  resolve();
}).then(function() {
  console.log("promise2");
});
// start->async1 start->promise1 ->async2 promise->promise2->async1 end->setTimeout

这样顺着这两个例子来推一推循环顺序,就可以基本理解了。

下面我们再说一下Node.js的Event Loop

node分三层构成

1.node-core

2.绑定

3.libuv + V8引擎

Node中的Event Loop是基于libuv实现的,而libuv是 Node 的新跨平台抽象层,libuv使用异步,事件驱动的编程方式,核心是提供I/O的事件循环和异步回调。libuv的API包含有时间,非阻塞的网络,异步文件操作,子进程等。 Event Loop就是在libuv中实现的。

Node的Event loop一共分为6个阶段,每个细节具体如下:

  1. timers:执行timer(定时器)的回调
  2. pending callbacks:系统操作的回调(待定回调执行延迟到下一个循环迭代的 I/O 回调。)
  3. idle,pepare:内部使用
  4. poll:等待新的I/O(输入/输出)事件(轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和setImmediate()调度的之外),其余情况 node 将在适当的时候在此阻塞。)
  5. check:执行setImmediate回调(检测)
  6. close callbacks:内部使用【关闭的回调函数:一些关闭的回调函数,如:socket.on('close', ...)】

 每个阶段都有一个 FIFO 队列来执行回调。虽然每个阶段都是特殊的,但通常情况下,当事件循环进入给定的阶段时,它将执行特定于该阶段的任何操作,然后执行该阶段队列中的回调,直到队列用尽或最大回调数已执行。当该队列已用尽或达到回调限制,事件循环将移动到下一阶段。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值