node生命周期
node声明周期也叫作node的事件循环,node的生命周期和浏览器并不一样,会比浏览器复杂一点,而且node在不同的操作系统上还有不同的差异,这里我们不涉及.

一开始运行入口文件,此时检查是否要进行事件循环,他其实就是在检查还有没有别的任务有没有结束,如果还有东西没有结束,比如还有计时器,或者其他线程还有一些任务在排队,那他就进入事件循环,事件循环运行的过程就是一圈一圈的循环检查,如果没有任何事情可以做了,那么就会结束事件循环,整个程序就会结束.
每一次事件循环就是一次轮循,一次事件循环有六个阶段,每一个阶段都会维护一个事件队列,每一次查看这个队列里有没有东西,如果有东西,全部执行完,然后继续轮循下一个队列,我们主要了解其中三个,分别是timers,poll,check
timers阶段是存放计时器的回调函数
poll队列是轮循队列,除了timers和check,绝大部分回调都会放入该队列,比如文件的读取,监听用户请求.poll队列的运作方式:如果poll中有回调函数,依次执行,直到清空队列,但是如果poll中没有回调,只要有任务没有结束,他就会在这里一直等着,当其他队列出现回调后,结束该阶段,进入下一阶段,重复一次事件循环,如果所有任务都结束了,poll也会立刻结束,所以程序等待时间最长的就在这个poll阶段,文件读取,用户请求这些都是等在这个阶段的.
check是检查阶段,这个阶段使用setImmediate的回调会直接进入这个队列,setImmediate类似于setTimeout设置一个0毫秒的延迟,setImmediate进入的队列就是check队列,而setTimeout进入的队列就是timers
为什么这里要设置一个check队列?先看一下timers队列里面的对比策略,timers队列里面有很多计时器,他是如何来看计时器有没有结束呢?他是把timers队列的计时器一个一个拿出来,看当前时间减去开始时间有没有超过时长,如果超过了就把回调函数拿出来执行,所以timers其实是在循环检查的策略,而check是一个正儿八经的队列,所以他的效率会比setTimeout高很多
看以下代码
javascript
setTimeout(() =>{
console.log("timeout");
},0)
setImmediate(() =>{
console.log("immediate")
});这里的先后顺序是不一定的,因为setTimeOut其实是取不到0的,我们设置0其实实际上是1,如果我们的事件循环到timer的时候,理想情况下setTimeOut是还没有执行完的,所以会先执行setImmediate,但如果我们计算机卡了一下,循环到timer的时候setTimeOut执行完了,就会先执行setTimeout函数,所以这个东西取决于计算机当时的状态
javascript
const fs = require("fs");
fs.readFile("./index.js",() =>{
setTimeout(() =>{console.log(1)});
setImmediate(() =>{console.log(2)});
});这里一定先输出2,因为setImmediate是立刻加入check的,而程序是在poll阶段等着的,poll的下一个阶段马上就是check
以上介绍的所有队列都是宏队列,除此之外,还有两个微队列,分别是nextTick和Promise,其中nextTick的优先级更高,微队列的优先级高于所有宏队列
事件循环每向前推进一步(执行每一个回调函数之前),必须先清空nextTick和Promise队列,可以使用prosess.nextTick()方法,参数为回调函数,就会将他加入到nextTick队列中
javascript
setImmediate(() =>{
console.log(1);
});
process.nextTick(() =>{
console.log(2);
process.nextTick(() =>{
console.log(6)
});
})
console.log(3);
Promise.resolve().then(() => {
console.log(4);
process.nextTick(() => {
console.log(5);
});
});输出结果为3 2 6 4 5 1
第一步,输出3,没有疑问,因为第10行代码会在事件循环之前实现,并且,在事件循环之前,check队列要输出1,nextTick队列要输出2,并且要向nextTick队列添加一个输出6的任务,Promise队列要输出4,并且要向nextTick队列添加一个输出5的任务,第一步会检查微队列,先检查nextTick,会立刻输出2,并且向nextTick队列添加一个输出6的任务,继续下一步,又会检查nextTick队列,发现有一个输出6的任务,所以就继续输出6,然后检查promise队列,有一个输出4的任务,然后再向nextTick队列添加一个输出5的任务,继续又会输出5,最后继续事件循环,最后输出1
javascript
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(function() {
console.log("setTimeout0");
}, 0);
setTimeout(function() {
console.log("setTimeout3");
}, 3);
setImmediate(() => console.log("setImmediate"));
process.nextTick(() => console.log("nextTick"));
async1();
new Promise(function(resolve) {
console.log("promise1");
resolve();
console.log("promise2");
}).then(function() {
console.log("promise3");
});
console.log("script end");