浏览器中的事件环,残缺事件环执行程序

  • 从上至下执行所有同步代码
  • 执行过程中遇到的宏工作与微工作增加至相应的队列
  • 同步代码执行结束后,执行满足条件的微工作回调。
  • 微工作队列执行结束后执行所有满足需要的宏工作回调
  • 循环事件环操作
  • 每执行一个宏工作之后就会立即查看微工作队列
setTimeout(() => {  console.log("s1");  Promise.resolve().then(() => {    console.log("p1");  });  Promise.resolve().then(() => {    console.log("p2");  });});setTimeout(() => {  console.log("s2");  Promise.resolve().then(() => {    console.log("p3");  });  Promise.resolve().then(() => {    console.log("p4");  });});// 打印s1p1p2s2p3p4

Node.js下的事件环

  • timers:执行setTimeout与setInterval回调
  • pending callbacks:执行零碎操作的回调,例如tcp udp
  • idle,prepare:只在零碎外部进行应用
  • poll:执行与IO相干的回调
  • check:执行setImmediate中的回调
  • close callbacks:执行close事件的回调
  • 执行同步代码,将不同的工作增加至相应的队列
  • 所有同步代码执行后回去执行满足条件微工作
  • 所有微工作代码执行后会执行timer队列中满足的宏工作
  • timer中的所有宏工作执行实现后就会顺次切换队列
  • 在实现队列切换之前会先清空微工作代码

案例代码

setTimeout(() => {  console.log("s1");});Promise.resolve().then(() => {  console.log("p1");});console.log("start");process.nextTick(() => {  console.log("tick");});setImmediate(() => {  console.log("setimmediate");});console.log("end");打印startendtickp1s1setimmediate// 1,setTimeout存入timer中// 2,promise进入微工作队列// 3,输入start// 4,nextTick进入微工作队列// 5,setImmediate进入check队列中// 6,输入end// 7,微工作中的tick优先级高于promise,先输入tick,后输入p1// 8,查看timer,输入s1// 9,查看poll,poll为空,查看check// 10,输入check中setimmediatesetTimeout(() => {  console.log("s1");  Promise.resolve().then(() => {    console.log("p1");  });  process.nextTick(() => {    console.log("t1");  });});Promise.resolve().then(() => {  console.log("p2");});console.log("start");setTimeout(() => {  console.log("s2");  Promise.resolve().then(() => {    console.log("p3");  });  process.nextTick(() => {    console.log("t2");  });});console.log("end");打印startendp2s1t1p1s2t2p3

nodejs与浏览器事件环差别

  • 工作队列数不同,浏览器只有两个队列,nodejs中有6个事件队列
  • 微工作执行机会不同,二者都会在同步代码执行完之后执行微工作,浏览器平台下每当一个宏工作执行结束后就清空微工作,nodejs平台在事件队列切换时会去清空微工作。
  • 微工作优先级不同,浏览器事件环中,微工作寄存于事件队列,先进先出,Nodejs中的process.nextTick先于promise.then

Nodejs事件环常见问题

setTimeout(() => {  console.log("timeout");},0);setImmediate(() => {  console.log("immdieate");});

疾速执行时,他们的打印程序可能会替换,setTimeout与setImmediate执行随机,setTimeout有延时。

const fs = require("fs");fs.readFile("./m1.js", () => {  setTimeout(() => {    console.log("timeout");  }, 0);  setImmediate(() => {    console.log("immdieate");  });});

在I/O操作的回调中,他们的打印程序固定,先打印immdieate再打印timeout。事件环中I/O回调在poll队列中执行之后查看微工作队列后切换到check中执行setImmediate,才会切换到timer中执行setTimeout