JS是单线程语言,始终只有一个线程执行JS代码(Web Worker没有改变JS单线程的本质),对于异步操做,是经过事件循环(Event Loop)来实现的。浏览器
每一个异步操做都是一个任务,任务分为宏任务和微任务bash
其中, setImmediate
和process.nextTick
是Node独有的,UI交互事件
确定是浏览器独有的。异步
特别是第二点,可能Node作了更新(当前时间是2019-01-13,Node v11.4.0),以下面代码,无论浏览器仍是Node,都会输出:1 2 3 4socket
setTimeout(function () {
new Promise(function (resolve) {
console.log(1);
resolve();
}).then(function () {
console.log(2);
});
});
setTimeout(function () {
new Promise(function (resolve) {
console.log(3);
resolve();
}).then(function () {
console.log(4);
});
});
// delay(); // 为了消除定时器最小延迟带来的影响,能够执行一下耗时操做,确保上面两个setTimeout都触发了
function delay() {
for (let i = 0; i < 1000000000; i++) {}
}
复制代码
定时器的最小延迟问题见这里oop
浏览器的事件循环是HTML5定义的规范,Node的事件循环是libuv库实现的,但截至目前(2019-01-13),二者的表现基本一致,Node的事件循环比浏览器要复杂,下面看Node的事件循环。post
Node的事件循环,每一轮有六个阶段测试
1. Timer阶段ui
执行可用的setTimeout/setInterval回调spa
2. I/O callbacks阶段线程
执行可用的I/O回调,除了setTimeout
、setInterval
、setImmediate
、Close callbacks
都属于这个阶段。
3. idle, prepare阶段
这两个阶段主要是Node作一些内部操做,忽略。
4. Poll阶段
这是轮询阶段,若是没有可用的setTimeout/setInterval/setImmediate/Close callbacks回调,会一直停留在这个阶段,等待I/O回调。
这个阶段不会一直停留,达到必定条件后,会到下一个阶段。
5. Check阶段
专门用于执行setImmediate
。
6. Close callbacks阶段
关闭请求在这里执行(socket.on('close', ()=>{})),这个阶段就像一个清理阶段。
若是事件循环还活着,就继续下一轮循环。
欢迎关注个人微博@狂刀二