一个 JavaScript 引擎会常驻于内存中,它等待着咱们把JavaScript 代码或者函数传递给它执行javascript
在 ES3 和更早的版本中,JavaScript 自己尚未异步执行代码的能力,引擎就把代码直接顺次执行了,异步任务都是宿主环境(浏览器)发起的(setTimeout、AJAX等)。html
在 ES5 以后,JavaScript 引入了 Promise,这样,不须要浏览器的安排,JavaScript 引擎自己也能够发起任务了java
js为单线程,js引擎中负责解析执行js代码的线程只有一个(主线程),即每次只能作一件事,其余IO操做放入任务队列等待执行,异步过程当中,工做线程在异步操做完成后须要通知主线程。那么这个通知机制是利用消息队列和事件循环(EventLoop)实际上,主线程只会作一件事情,就是从消息队列里面取消息、执行消息,再取消息、再执行。当消息队列为空时,就会等待直到消息队列变成非空。并且主线程只有在将当前的消息执行完成后,才会去取下一个消息
node:node.js单线程只是一个js主线程,本质上的异步操做仍是由线程池完成的,node将全部的阻塞操做都交给了内部的线程池去实现,自己只负责不断的往返调度,并无进行真正的I/O操做,从而实现异步非阻塞I/O,这即是node单线程的精髓之处了。node
微任务:git
宏任务github
过程promise
每次事件循环都包含了6个阶段浏览器
setTimeout
、setInterval
)的回调setImmediate()
的回调socket
的 close
事件回调Node 会去检查有无已过时的timer,若是有则把它的回调压入timer的任务队列中等待执行网络
技术上来讲,poll 阶段控制 timers 何时执行。异步
poll 阶段
poll 阶段主要有2个功能:
执行过程:当event loop进入 poll 阶段,而且 没有设定的timers(there are no timers scheduled),会发生下面两件事之一:
若是 poll 队列不空,event loop会遍历队列并同步执行回调,直到队列清空或执行的回调数到达系统上限;
若是 poll 队列为空,则发生如下两件事之一:
setImmediate()
会致使event loop阻塞在poll阶段,这样以前设置的timer岂不是执行不了了?因此咧,在poll阶段event loop会有一个检查机制,检查timer队列是否为空,若是timer队列非空,event loop就开始下一轮事件循环,即从新进入到timer阶段。process.nextTick()
process.nextTick()
,会致使出现I/O starving(饥饿)setImmediate
setTimeout(()=>{ console.log('timer1') Promise.resolve().then(function() { console.log('promise1') }) }, 0) setTimeout(()=>{ console.log('timer2') Promise.resolve().then(function() { console.log('promise2') }) }, 0) //浏览器: timer1 promise1 timer2 promise2 // node timer1 timer2 promise1 promise2
http://lynnelv.github.io/img/...
http://lynnelv.github.io/img/...
https://juejin.im/post/5b61d8...
https://yq.aliyun.com/article...
https://juejin.im/post/5b1e55...