Concepteventloop概览┌──────────────────────────────┐┌─>│定时器│(本阶段执行由setTimeout()和setInterval())安排的回调│└──────────────┬──────────────┘│┌──────────────┴──────────────┐││挂起的回调│(执行延迟到下一个循环迭代的I/O回调。)│└────────────────┬────────────┘│┌──────────────┴──────────────┐││空闲,准备│(仅内部使用)│└──────────────┬──────────────┘┌────────────────┐│┌────────────┴──────────────┐│传入:│││民意调查│<──────┤连接,│(检索新的I/O事件;执行I/O相关回调)│└────────────────┬─────────────┘│数据等││┌──────────────┴──────────────┐└──────────────────┘││检查│(这里调用setImmediate()回调)│└──────────────┬──────────────┘│┌──────────────┴──────────────┐└──┤关闭callBacks│(一些关闭回调,例如Socket.on('close',...))────────────────────────┘──────────┘──────────────┘──────────────────────┘──┘详情请参考https://nodejs.org/en/docs/gu...Macrotask和Microtask参考https://stackoverflow.com/que...:一个eventloop的循环会从macrotask队列中取出一个task,task之后完成后,微任务队列的所有微任务都会被处理,然后继续从宏任务队列中取任务……微任务在被处理的过程中可以创建其他的微任务,这些微任务也会被添加到微任务队列中并被一个一个执行上面说了,如果一个microtask不停地创建新的microtask,可能会导致其他macrotasks“饿死”,因为microtask队列很难清空。示例:宏任务:setTimeout、setInterval、setImmediate、requestAnimationFrame、I/O、UI渲染微任务:process.nextTick、Promises、Object.observe、MutationObserverExampleJScodeconsole.log('mainthreadstart...');setTimeout(()=>console.log('Timeout1'),0);//宏任务queueletpromiseF=()=>newPromise(resolve=>setTimeout(()=>resolve('Timeout3'),0));letasyncF=async()=>console.log(awaitpromiseF());异步F();//因为async会用promise包装结果,"console.log(awaitpromiseF())""进入Microtaskletp1=Promise.resolve('p1');letp2=Promise.resolve('p2');p1.then(r=>{console.log(r);//p1setTimeout(()=>console.log('Timeout2'),0);//宏任务队列constp3=Promise.resolve('p3');p3.then(console.log);//p3});//微任务queuep2.then(console.log);//p2setTimeout(()=>console.log('Timeout4'),0);//Macrotaskconsole.log('mainthreadend.');上面程序运行的结果如接下来:mainthreadstart...mainthreadend.p1p2p3Timeout1Timeout4Timeout2Timeout3Executivesequentialsynchronouscodeexecutionconsole.log('mainthreadstart...');,然后打印logmainthreadstart....will()=>console.log('Timeout1')这个回调任务被添加到宏任务队列中。调用asyncF()函数,因为这个函数是async函数,所以会把console.log(awaitpromiseF())包装成promise,可以看做是promise.then(...),所以console.log(awaitpromiseF())将被添加到微任务队列中。p1.then(...)和p2.then(...)也将被添加到微任务队列中。将()=>console.log('Timeout4')的回调函数添加到宏任务队列中。执行console.log('mainthreadend.');,然后打印mainthreadend。上面的操作完成后,Macrotask队列和Microtask队列会是这样的:Macrotask队列Microtask队列┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐|console.log('Timeout1')||console.log(awaitpromiseF())|└────────────────────────────────┘└──────────────────────────────────────────┘|console.log('Timeout4')||p1.then(...)|└───────────────────────────────────────────────────────────────────────────────────────────────────┘|p2.then(...)|└─────────────────────────────────────┘按照first-的原则处理微任务队列在first-outfirstprocessconsole.log(awaitpromiseF())中,我们可以把await当做一个microtask,所以microtask队列看起来是这样的:Microtaskqueue┌───────────────────────────────────────────────────────────┐|p1.then(...)|└───────────────────────────────────────────────────────────────────────────────────────────────────────┘|p2.then(...)|└────────────────────────────────────────────────────────────────────────────────────────┘|setTimeout(()=>resolve('Timeout3'),0)|└──────────────────────────────────────────────────────┘Processp1.then(...),print"p1",addconsole.log('Timeout2')到宏任务队列,并将p3.then(...)添加到微任务队列。宏任务队列微任务队列┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐|控制台日志('超时1')||p2.then(...)|└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘|console.log('Timeout4')||setTimeout(()=>resolve('Timeout3'),0)|└──────────────────────────────────────┘└────────────────────────────────────────────────────────┘|console.log('Timeout2')||p3。然后(...)|└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘处理p2.then(...),打印p2,然后执行setTimeout(()=>resolve('Timeout3'),0),加上resolve('Timeout3')宏任务队列,然后打印p3。宏任务队列┌──────────────────────────────┐|console.log('Timeout1')|└────────────────────────────────┘|console.log('Timeout4')|└──────────────────────────────┘|console.log('Timeout2')|└────────────────────────────────┘|resolve('Timeout3')|└──────────────────────────────┘最后清空所有macrotask队列(即处理完所有macrotasks)因此,最终的打印结果是mainthreadstart...mainthreadend.p1p2p3Timeout1Timeout4Timeout2Timeout3
