Event Loop机制

文章详细阐述了EventLoop的工作原理,包括浏览器和Node.js环境下的差异。宏任务如script、setTimeout和setImmediate,以及微任务如Promise、MutationObserver和process.nextTick在事件循环中的执行顺序被详尽解析。同时,文章提到了Node.js的事件循环六个阶段,并通过示例代码解释了它们如何影响异步操作的执行顺序。
摘要由CSDN通过智能技术生成

Event Loops标准

HTML Standard  

标准对Event Loops的说明

Node.js 事件循环,定时器和 process.nextTick()

Node.js 事件循环,定时器和 process.nextTick() | Node.js  

介绍了nodejs的事件循环和定时器

调用栈

Call stack(调用栈) - MDN Web 文档术语表:Web 相关术语的定义 | MDN  

介绍js运行调用栈

JS中的栈内存堆内存

「前端进阶」JS中的栈内存堆内存 - 掘金  

浏览器端运行JS;V8引擎开源后,JS有机会在服务端运行

浏览器的Event Loop

异步实现:

1.宏观:浏览器多线程

2.微观:Event Loop,事件循环

Task(普通任务,宏任务) :setImmediate(node 的立即执行函数先于setTimeout执行)

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

 下图紫色部分就是Event Loop (事件循环)

 

 

1.首先执行script,script被称为全局任务,也属于task(宏任务);

2.当task执行完以后,执行所有的微任务;

3.微任务全部执行完,再取任务队列中的一个宏任务执行。

一个Event Loop有一个或多个task queue(宏任务队列),每个Event Loop有一个microtask queue(微任务队列)

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

 

console.log("1");
setTimeout(function() {
  console.log("2");
}, 0);
Promise.resolve().then(function() {
  console.log("3");
});
console.log("4");
// 1->4->3->2
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

分3层构成

1.node-core

2.绑定

3.libuv + V8引擎

六个阶段:

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

 

 

// nodejs模块——fs模块 fs模块用于对系统文件及目录进行读写操作。
const fs = require('fs');// fs.xxx 异步js方法
function someAsyncOperation(callback) {
  fs.readFile(__dirname, callback);
}
const timeoutScheduled = Date.now();
setTimeout(() => {
  const delay = Date.now() - timeoutScheduled;
  console.log(`${delay}ms have passed since I was scheduled`);// 204ms=加载文件4ms + 休息200ms ≠ 100ms,poll会阻塞进程
}, 100);
someAsyncOperation(() => {
  const startCallback = Date.now();
  while (Date.now() - startCallback < 200) {
    // do nothing休息200ms
  }
});

如果运行以下不在 I/O 周期(即主模块)内的脚本,则执行两个计时器的顺序是非确定性的,因为它受进程性能的约束:

// timeout_vs_immediate.js
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

但是,如果你把这两个函数放入一个 I/O 循环内调用,setImmediate 总是被优先调用

const fs = require('fs');
fs.readFile(__filename, _ => {
  setTimeout(_ => {
    console.log("setTimeout");
  }, 0);
  setImmediate(_ => {
    console.log("setImmediate");
  });
});
// setImmediate->setTimeout

process.nextTick()

是一个异步的node API,但是不属于Event Loop的阶段

调用这个方法会先暂停Event Loop,先执行这个方法回调,之后继续Event Loop

const fs = require("fs");
fs.readFile(__filename, _ => {
  setTimeout(_ => {
    console.log("setTimeout");
  }, 0);
  setImmediate(_ => {
    console.log("setImmediate");
    process.nextTick(_ => {
      console.log("nextTick2");
    });
  });
  process.nextTick(_ => {
    console.log("nextTick1");
  });
});
// nextTick1->setImmediate->nextTick2->setTimeout

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值