1.介绍
事件循环机制是Node.js最重要的一部分之一。
为什么他这么重要呢?因为它解释了为什么Node.js(单线程)能够是异步的,并且不会阻塞IO。
Node.js能够做到这些,离不开调用栈、音讯队列和ES6工作队列。
2.调用栈
在执行javascript脚本的时候会程序执行,讲执行的函数依照程序入栈,执行完之后退出栈。
例子如下:
test1() { console.log('test1');}test2() { console.log('test2');}test3() { console.log('test3 start'); test1(); test2(); console.log('test3 end');}test3();
执行这个脚本会失去如下后果:
test3 starttest1test2test3 end
调用栈依照一下顺序调用:
1.调用test3()
|__test3__|
2.执行test3()
|__console.log("test3 start")__|
|__________test3___________ |
3.test1()入栈并执行
|__console.log("test1")__|
|______test1___________|
|______test3___________|
test1执行完之后退栈
4.test2()入栈并执行
|__console.log("test2")__|
|______test2___________|
|______test3___________|
test2执行完之后退栈
5.继续执行test3
|__console.log("test3 end")__|
|__________test3___________|
test3执行完之后退栈
3.音讯队列
如果只应用一个调用栈,那么当一个函数执行工夫很长时,这个函数会阻塞前面的须要被调用的函数。
因而,将那些会阻塞其余失常函数执行的函数(用户发动的事件)放在音讯队列中,如定时器、单击或键盘事件、Dom事件。
例子:
test1() { console.log('test1');}test2() { console.log('test2');}test3() { setTimeOut(()=> console.log('last'),0); test1(); test2(); console.log('test3 end');}test3();
执行这个脚本会失去如下后果:
test1test2test3 endlast
执行过程如下:
1.执行test3()并入栈
|__test3__|
2.执行setTimeOut并入队列
栈:
|__setTimeOut(xxx)__|
|_____test3_________|
队列:
| console.log('last') |
3.test1()入栈并执行
|__console.log("test1")__|
|______test1___________|
|______test3___________|
test1执行完之后退栈
4.test2()入栈并执行
|__console.log("test2")__|
|______test2___________|
|______test3___________|
test2执行完之后退栈
5.继续执行test3
|__console.log("test3 end")__|
|__________test3___________|
test3执行完之后退栈
6.栈空之后执行音讯队列内容
队列:
| console.log('last') |
这个线程会先去执行调用栈,调用栈空之后心才会去执行音讯队列中的内容。
4.ES6工作队列
ECMAScript 2015 / ES6 引进的工作队列的概念,这个工作队列会将promise放进去。
音讯队列和工作队列之间的关系能够用在游乐园坐过山车来比喻:
音讯队列把你放在队列的前面,在所有其他人的前面,你必须在那里期待轮到你,而工作队列是疾速通行证 这样您就能够在实现上一次骑行后立刻进行另一次骑行。
例子:
test1() { console.log('test1');}test2() { console.log('test2');}test3() { setTimeOut(()=> console.log('last'),0); new Promise((resolve,reject)=>{ resole('before last'); }).then(res => console.log(res)); test1(); test2(); console.log('test3 end');}test3();
执行这个脚本会失去如下后果:
test1test2test3 endbefore lastlast
执行过程如下:
1.执行test3()并入栈
|__test3__|
2.执行setTimeOut并入音讯队列
栈:
|__setTimeOut(xxx)__|
|_____test3_________|
音讯队列:
| console.log('last') |
3.执行promise并入工作队列
栈:
|__resole(xxx)_______|
|_____test3_________|
工作列:
| console.log('before last') |
4.test1()入栈并执行
|__console.log("test1")__|
|______test1___________|
|______test3___________|
test1执行完之后退栈
5.test2()入栈并执行
|__console.log("test2")__|
|______test2___________|
|______test3___________|
test2执行完之后退栈
6.继续执行test3
|__console.log("test3 end")__|
|__________test3___________|
test3执行完之后退栈
7.栈空之后执行音讯队列内容
队列:
| console.log('last') |
8.栈空之后执行工作队列内容
队列:
| console.log('before last') |