当前位置: 首页 > 后端技术 > Node.js

浏览器和Node.js中的事件循环

时间:2023-04-04 01:34:34 Node.js

浏览器中的事件循环,完整的事件循环执行顺序从上到下执行所有同步代码执行过程中遇到的宏任务和微任务都添加到对应的queueforsynchronization代码执行后,执行满足条件的微任务回调。microtask队列执行完毕后,执行所有满足要求的macrotasks。回调循环事件循环操作将在每个宏任务执行后立即检查微任务队列。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");});});//打印s1p1p2s2p3p4Node.js下的事件环timers:执行setTimeout和setInterval回调pendingcallbacks:执行系统操作的回调,比如tcpudpidleprepare:只在系统内使用poll:执行IO相关的回调check:执行setImmediate中的回调closecallbacks:执行close事件的回调执行同步代码,将不同的任务添加到对应的队列后返回执行allsynchronouscodeisexecuted满足条件的微任务会在所有微任务代码执行完毕后执行。定时器队列中满足要求的宏任务将被执行。定时器中的所有宏任务执行完毕后,会依次切换队列。在队列切换完成之前,先清除微任务代码┌────────────────────────────────┐┌──>│计时器││└────────────────┬──────────────────┘│┌──────────────────────────────────────────────────────────┐││等待回调││└────────────────┬──────────────────┘│┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐││空闲,准备│-────────────┴──────────────┐│传入:│││投票│<──────┤连接,││└────────────────┬──────────────────┘│数据等────────────┐└──────────────────────┘││检查││└──────────────────────────┬────────────────┘│┌────────────────────────────────────────────────┐└──┤收盘回调│└──────────────────────────────────┘每个框称为事件循环机制的一个阶段每个阶段都有一个FIFO队列来执行回调。虽然每个阶段都是特殊的,但一般来说,当事件循环进入给定阶段时,它会执行该阶段特定的任何操作,然后执行阶段队列中的回调,直到队列耗尽。已执行所有或最大数量的回调。当该队列耗尽或达到回调限制时,事件循环将进入下一阶段,依此类推。加入微任务──────────────────────────┐│同步代码│└──────────────────────┬────────────────────┘┌──────────────────────────────────────────────────────┐│process.nextTick││promise.then()│└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐┌——————————————————定时器│└────────────────────────────┘│┌────────────────┴────────────────┐││等待回调││└────────────────┬──────────────────┘│┌──────────────┴────────────────────┐││空闲,准备...──────────────┴──────────────────────┐│传入:│││投票│<──────┤连接,││└──────────────┬────────────────────┘│数据等││┌──────────────────────────┴──────────────┐└───────────────────────────────────────────────────────────────────────┘││检查││└────────────────────────────────────────────────────────────————————┬──────────────────┘│┌────────────────┴────────────────┐└──┤关闭回调│└────────────────────────────────────────——┘CasecodesetTimeout(()=>{console.log("s1");});Promise.resolve().then(()=>{console.log("p1");});console.log("start");process.nextTick(()=>{console.log("tick");});setImmediate(()=>{console.log("setimmediate");});console.log("结束");printstartendtickp1s1setimmediate//1、setTimeout存入定时器//2、promise进入微任务队列//3、输出start//4、nextTick进入微任务队列//5、setImmediate进入check队列//6、outputsend//7,微任务中的tick优先级高于promise,先输出tick,再输出p1//8,checktimer,输出s1//9,checkpoll,poll为空,checkcheck//10,输出检查=>{console.log("t1");});});Promise.resolve()。然后(()=>{console.log("p2");});安慰。日志(“开始”);setTimeout(()=>{console.log("s2");Promise.resolve().then(()=>{console.log("p3");});process.nextTick(()=>{console.log("t2");});});console.log("end");printstartendp2s1t1p1s2t2p3nodejs不同于浏览器事件环数不同的任务队列。浏览器只有两个队列。nodejs中有6个不同执行时机的事件队列微任务。两者都会在同步代码执行完后执行微任务。浏览器平台下每次宏任务任务执行完毕后,微任务会被清除。nodejs平台会在promise.thenNodejs事件循环FAQ之前切换事件队列时清空microtasksetTimeout(()=>{console.log("timeout");},0);setImmediate(()=>{console.log("immdieate");});fast执行时,它们的打印顺序可能会互换,setTimeout和setImmediate是随机执行的,setTimeout有延迟。constfs=require("fs");fs.readFile("./m1.js",()=>{setTimeout(()=>{console.log("timeout");},0);setImmediate(()=>{console.log("即刻");});});在I/O操作的回调中,它们的打印顺序是固定的,先打印immdieate,再打印timeout。在poll队列中执行完eventring中的I/O回调后,查看microtask队列,切换到check执行setImmediate,再切换到timer执行setTimeout