大家都知道javascript是单线程语言,所以为了实现主线程的非阻塞,EventLoop这样的解决方案应运而生。浏览器中的事件循环与节点中的不同。浏览器中的事件循环是HTML5中定义的规范,而node中的事件循环是由libuv库实现的。浏览器中事件循环的所有同步任务都在主线程上执行,形成一个执行栈。除了主线程,还有一个任务队列。任务队列分为宏任务(macrotask)和微任务(microtask)。macro-task(宏任务):setTimeout、setInterval、setImmediate、I/O等micro-task(微任务):process.nextTick、nativePromise(有些实现的promise将then方法放在宏任务中)、Object.observe(Deprecated)、MutationObserver和整个最基本的EventLoop如图所示:具体流程:在浏览器中,先执行当前栈,然后执行主执行线程中的任务。取出Microtask微任务队列中的任务执行,直到清空。在Macrotask宏任务中取出一个任务执行。检查Microtask微任务中是否有任务,如果有则执行直到被清除。重复3和4,整个运行机制也叫事件循环(EventLoop)例子了解浏览器的事件循环后,查看下面的例子,猜猜浏览器是如何输出console.log(1);console.log(2);setTimeout(function(){console.log('setTimeout1');Promise.resolve().then(function(){console.log('Promise')})})setTimeout(function(){console.log('setTimeout2');})//浏览器输出:12setTimeout1PromisesetTimeout2node中的事件循环在libuv内部就有这样的事件循环机制。事件环在节点启动时初始化。Node中的事件循环分为6个阶段。与浏览器不同,每个阶段对应一个事件队列。Node会执行当前阶段的所有任务,清除NextTickQueue,清除MicrotaskQueue,然后执行下一个阶段。在node.js中,process对象代表node.js应用,可以获取应用的用户、运行环境等各种信息。process.nextTick()方法将回调添加到nexttick队列中,nextTick的优先级高于promise等微任务。timers:执行setTimeout()和setInterval()中的过期回调。I/O回调:上一个周期的少量I/O回调会延迟到本轮这个阶段执行idle,prepare:移动队列,内部只使用poll:最重要的阶段,执行I/O回调,它将在适当的条件下阻塞。此阶段检查:ExecutethecallbackofsetImmediateclosecallbacks:执行close事件的回调,比如socket.on("close",func)的例子检查下面的例子加深对事件循环的理解Executeinnode在下面的代码中,发现每次执行的顺序都不一样,因为node需要启动时间,setTimeout在执行的时候可能定时也可能不定时,所以顺序取决于node的执行时间。setTimeout(function(){console.log('timeout')})setImmediate(function(){console.log('immediate')})i/o操作阶段完成后,进入check阶段,所以setImmediate将优先考虑'timeout')})setImmediate(funciton(){console.log('setTimmediate')})})nextTick应用场景functionFn(){this.arrs;process.nextTick(()=>{//根据nextTick的特点,可以先赋值,然后在next队列中使用this.arrs();})}Fn.prototype.then=function(){this.arrs=function(){console.log(1)}}letfn=newFn();fn.then();//注意:nextTick一定不能写递归,否则会造成死循环。您可以放置??一些在setTimeout之前执行的任务。在相同的上下文中,MicroTask微任务将在MacroTask宏任务之前运行。浏览器首先抓取一个MacroTask执行,然后执行MicroTask中的所有任务。节点分六个阶段执行。每个阶段切换时,同一个MicroTask队列中的process.tick()会比PromisesetImmdieate()和setTimeout()好。如果是异步i/o回调之间的外部调用(I/O内部调用,因为下一阶段是check阶段),执行的顺序是不确定的,要看循环执行前的耗时情况。
