node简介
- node.js是一个基于ChromeV8引擎的js运行环境
- node.js使用commonjs模块化规范
- 在node中,每一个模块就是一个js文件,每个模块都被一个函数包裹,但这个函数被隐藏了,这个时候可以用 arguments 来找到它
在node中输入
console.log(arguments.callee.toString());就可以拿到包裹函数的实参 这5个参数代表
exports 暴露
require 引入
module 暴露
__filename 当前模块文件的绝对路径
__dirname 当前模块文件的相对路径
- 在node中是不存在Dom的,绝大部分Bom也不存在,node中不存在window对象,它通过global来取代了window
轮询机制
言归正传,node的事件轮询机制并不同于浏览器的事件轮询机制,具体如下
1. 定时器:
本阶段执行已经安排的 setTimeout() 和 setInterval() 的回调函数。
2. 待定回调:
执行延迟到下一个循环迭代的 I/O 回调。
TCP错误回调函数
3. idle, prepare:
仅系统内部使用。
4. 轮询:
轮询回调队列:需要将来执行的回调函数
轮询轮询回调队列,看是否由回调函数要执行
- 轮询回调队列有内容
直到轮询回调队列为空
- 轮询回调队列没有内容
如果之前设置过setImmediate函数,就去下一个阶段
如果没有设置过,就在当前阶段等待(等待新的回调函数被添加进来)
特殊:如果定时器时间到了,也会去下一个阶段
5. 检测:
setImmediate() 回调函数在这里执行。
6. 关闭的回调函数:
执行关闭事件的回调函数 close end
这里要说明一下,事件轮询是无限的死循环,到了最后一步后又会返回第一步, 还有就是process.nextTick函数会在任意阶段,优先执行。先看一段简单的代码
setTimeout(() => {
console.log(1);
}, 0);
setImmediate(() => {
console.log(2);
});
process.nextTick(() => {
console.log(3);
});
console.log(4);
毋庸置疑,最先输出的肯定是4,然后这段代码的回调队列为 [setTimeout, setImmediate, process.nextTick], 因为process.nextTick会优先执行,所以接下来输出3,此时回调队列为 [setTimeout, setImmediate], 依次取出,同步执行,输出1和2。 最终结果为 4,3,1,2
在来看一段稍微复杂一点的
setTimeout(() => { //setTimeout1
console.log(1);
setTimeout(() => { //setTimeout2
console.log(2);
}, 0);
setImmediate(() => { //setImmediate2
console.log(3);
});
process.nextTick(() => { //process2
console.log(4);
});
}, 0);
setImmediate(() => { //setImmediate1
console.log(5);
});
process.nextTick(() => { //process1
console.log(6);
});
console.log(7);
先一点点解析,代码解析完后,此时的回调队列应为 【setTimeout1, setImmediate1, process1】,因为此时setTimeout1的回调函数并没有执行,所以里面的函数没有添加到回调队列,然后process1会插队,所以前两个输出 7,6, 接下来开始执行setTimeout1,此时会接着输出1,然后其他函数会添加到回调队列,这个时候回调队列应为【setImmediate1, setTimeout2, setImmediate2, process2】,process2优先输出,最终结果为 7,6,1,4,5,3,2
这里可能有人会不懂为什么先输出3,而不是先输出2,这里回到事件轮询机制的第一步,执行完setTimeout1之后,setImmediate2已被添加到第5步的队列中,所以先输出3,执行完第6步之后,在开始下一次事件轮询的时候执行setTimeout2
再来最后一段代码
setImmediate(() => {
console.log(1);
})
Promise.resolve()
.then(() => {
console.log(2);
setImmediate(() => {
console.log(3);
})
process.nextTick(() => {
console.log(4);
})
})
.then(() => {
console.log(5);
})
process.nextTick(() => {
console.log(6);
})
console.log(7);
输出结果为7,6,2,5,4,1,3 这里简单说一下宏任务与微任务
宏任务
| 浏览器 | Node | |
|---|---|---|
| setTimeout | √ | √ |
| setInterval | √ | |
| setImmediate | x | √ |
| requestAnimationFrame | √ | x |
微任务
| 浏览器 | Node | |
|---|---|---|
| process.nextTick | x | √ |
| MutationObserver | √ | x |
| Promise.then catch finally | √ | √ |
宏任务与微任务之间的关系图

要给微任务一个优先级的话,就是同一层级的优先执行,下一层级后执行,如上面这段代码所示,先输出5,后输出4。