浏览器的EventLoop异步实现宏:浏览器多线程微:EventLoopEventCycle,实现异步的一种机制资料:EventLoopsStandardMessageQueue和EventCycle(写的很清楚)宏task和微任务宏任务(macrotask)JavaScript脚本执行事件setTimeout/setInterval定时器setImmediateI/O操作UI渲染微任务(微任务)PromiseObject.observeMutationObserverpostMessage信息:宏任务和微任务(分析的很详细)Event的紫色部分Loop运行过程就是EventLoop过程在JS中的栈内存栈。实施。如果调用栈中正在执行的函数还调用了其他函数,则新函数也会被添加到调用栈中。一旦调用此函数,它将立即执行。当前函数执行完毕后,解释器将其从调用栈中清除,继续执行当前执行环境中剩余的代码。调用该函数时,会调用一些异步函数(定时器、Promise、Ajax等),相应异步处理模块对应的线程会向任务队列中添加事件。从任务队列中取出一个宏任务。当macrotask执行完,调用栈为空时,会执行所有microtasks(一个需要异步执行的函数,执行时机在main函数执行后,当前macrotask结束前。).继续事件循环,然后在任务队列中取一个宏任务执行。EventLoop处理模型代码分析1:console.log("1");setTimeout(function(){console.log("2");},0);Promise.resolve().then(function(){console.log("3");});console.log("4");//输出:1432执行过程:目前是宏任务,顺序执行,打印完14,宏任务队列为空查看Microtask队列,执行Promise.resolve().then(),打印3,microtask队列为空重新渲染,任务队列中有定时器任务,执行,打印2一个EventLoop有一个or更多任务队列,每个事件循环都有一个微任务队列。requestAnimatinFrame不在任务队列中,处于渲染阶段。(待学习)代码示例2:newPromise()执行时会同步执行newPromise()传入的函数参数console.log("start");setTimeout(()=>{console.log("setTimeout");newPromise(resolve=>{console.log("promiseinner1");resolve();}).then(()=>{console.log("promisethen1");});},0);newPromise(resolve=>{console.log("promiseinner2");resolve();}).then(()=>{console.log("promisethen2");});//start//promiseinner2这一步是同步执行的//这里的promisethen2是异步的,微任务//setTimeout//promiseinner1//promisethen1打印startnewPromise()传入的函数参数,会在执行过程中执行newPromise()操作同步执行,打印promiseinner2执行microtask,打印promisethen2事件循环,执行宏任务setTimeout,打印setTimeout执行newPromise(),打印promiseinner1执行microtask,打印promisethen1代码示例3:异步函数async1(){console.log("async1start");等待async2();console.log("async1end");}asyncfunctionasync2(){returnPromise.resolve().then(_=>{console.log("async2promise");});}console.log("start");setTimeout(function(){console.log("setTimeout");},0);async1();newPromise(function(resolve){console.log("promise1");resolve();}).then(function(){console.log("promise2");});/*startasync1startpromise1async2promisepromise2async1endsetTimeout*/打印“start”执行异步函数async1,打印“async1start”执行awaitasync2();async2也是一个async函数,返回一个Promise对象,这里是一个microtask,放到microtask队列中await正在等待后面函数的执行结果,所以这里暂停。执行newPromise()并打印“promise1”。这里还有一个microtask,也是放到microtask队列中的。宏任务执行完毕,现在查看微任务队列,按顺序执行,先打印“async2promise”,再打印“promise2”。当前任务结束。进入下一个事件循环,将setTimeout的时间设置为0,肯定是到了,setTimeout已经在任务队列中了,执行,打印“setTimeout”。Node.jsEventLoopNode.js架构图node-coreAPI核心JS库绑定负责封装和暴露libuv和JSV8引擎的其他底层功能JS引擎是JS在服务端运行的基础I/libuv底层的ONode引擎负责NodeAPI的执行,将不同的任务分配给不同的线程,并将任务的执行结果以异步的方式返回给V8引擎,这是Node异步的基础编程。Node.jsEventLoop的六个阶段Node.js官方文档定时器(timer)执行定时器回调挂起回调(pendingcallbacks)系统运行回调idle,prepare内部使用轮询(polling)等待新的I/O事件检查(detection)执行setImmeidatecallbackclosecallbacks(关闭回调函数)内部使用主要需要注意阶段1、4、5,每个阶段都有一个先进先出的队列需要执行回调。当事件循环运行到指定阶段时,将执行该阶段的FIFO队列。当执行完队列的回调或者执行的回调数超过该阶段的上限时,事件循环将转入下一阶段。poll阶段的主要功能:计算应该阻塞多长时间(需要等待I/O操作)来处理poll队列的事件代码分析1:constfs=require('fs');functionsomeAsyncOperation(回调){fs.readFile(__dirname,回调));//异步读取文件}consttimeoutScheduled=Date.now();//当前时间setTimeout(()=>{constdelay=Date.now()-timeoutScheduled;console.log(`${delay}mshavepassedsinceIwasscheduled`);//在多少毫秒后执行},100);someAsyncOperation(()=>{conststartCallback=Date.now();//延迟200mswhile(Date.now()-startCallback<200){//什么都不做}});/*输出:204ms已经过去了,因为我被scheduledsomeAsyncOperation读取文件后(4ms),进入poll阶段执行回调,sleep200ms,poll为空,检查时间是否有定时器,执行setTimeout*/代码分析2:constfs=require('FS');fs.readFile(__filename,()=>{setTimeout(()=>{console.log("setTimeout");},0);setImmediate(()=>{console.log("setImmediate");});});/*输出:setImmediatesetTimeout读取文件后,执行回调。如果setImmediate的回调进入check阶段,会等待回调加入轮询队列。所以首先输出setImmediate*/process.nextTick()是一个例外Step节点API,但是在不属于事件循环的阶段调用nextTick时,会停止事件循环,在继续执行事件循环之前先执行nextTick回调constfs=require("fs");fs.readFile(__filename,()=>{setTimeout(()=>{console.log("setTimeout");},0);setImmediate(()=>{console.log("setImmediate");process.nextTick(()=>{console.log("nextTick2");});});process.nextTick(()=>{console.log("nextTick1");});});/*nextTick1setImmediatenextTick2setTimeout*/
