西门吹雪 2019-07-01
一个 JavaScript 引擎会常驻于内存中,它等待着我们把JavaScript 代码或者函数传递给它执行
在 ES3 和更早的版本中,JavaScript 本身还没有异步执行代码的能力,引擎就把代码直接顺次执行了,异步任务都是宿主环境(浏览器)发起的(setTimeout、AJAX等)。
在 ES5 之后,JavaScript 引入了 Promise,这样,不需要浏览器的安排,JavaScript 引擎本身也可以发起任务了
js为单线程,js引擎中负责解析执行js代码的线程只有一个(主线程),即每次只能做一件事,其他IO操作放入任务队列等待执行,异步过程中,工作线程在异步操作完成后需要通知主线程。那么这个通知机制是利用消息队列和事件循环(EventLoop)实际上,主线程只会做一件事情,就是从消息队列里面取消息、执行消息,再取消息、再执行。当消息队列为空时,就会等待直到消息队列变成非空。而且主线程只有在将当前的消息执行完成后,才会去取下一个消息
node:node.js单线程只是一个js主线程,本质上的异步操作还是由线程池完成的,node将所有的阻塞操作都交给了内部的线程池去实现,本身只负责不断的往返调度,并没有进行真正的I/O操作,从而实现异步非阻塞I/O,这便是node单线程的精髓之处了。
微任务:
宏任务
过程
每次事件循环都包含了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...